python redis分布式锁改进
0X01 python redis分布式锁通用方法
REDIS分布式锁实现的方式:SETNX + GETSET
python 版本实现上述思路(案例1)
但是,流通的代码 redis锁中有BUG,有考虑不周的点。
0X02 时间戳变为str形式
time.time() > cls.rdcon.get(cls.lock_key)
写法不正确。time.time()为浮点型,redis get取得的为字符串型。
python 中,字符串与浮点型对比,字符串大。
>>> a = "0.003"
>>> b = 1000000
>>> a >b
True
>>> a < b
False
>>>
于是
if cls._lock == 1 or (time.time() > cls.rdcon.get(cls.lock_key) and time.time() > cls.rdcon.getset(cls.lock_key, timestamp)):
变成
if cls._lock == 1 or (time.time() > float(cls.rdcon.get(cls.lock_key)) and time.time() > float(cls.rdcon.getset(cls.lock_key, timestamp))):
0X03 竞争条件下的float
在代码运行到任何一处地方,锁都可能释放。
比如,刚开始拿不到锁, cls._lock!=1,走向or。
这时锁释放了,redis中取出了None,float(None)报错。
或者getset获得了None(说明写入成功),float(None)报错。
float中可能是数值型,也可能是None型。
改进(同时取函数的第二个参数作为标识id)
#!/usr/bin/env python
# coding=utf-8
import time
import redis
from conf.config import REDIS_HOST, REDIS_PORT, REDIS_PASSWORD
class RedisLock(object):
def __init__(self):
self.rdcon = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, password=REDIS_PASSWORD, db=1)
self._lock = 0
self.lock_key = ""
@staticmethod
def my_float(timestamp):
"""
Args:
timestamp:
Returns:
float或者0
如果取出的是None,说明原本锁并没人用,getset已经写入,返回0,可以继续操作。
"""
if timestamp:
return float(timestamp)
else:
return 0
@staticmethod
def get_lock(cls, key, timeout=10):
cls.lock_key = "%s_dynamic_lock" % key
while cls._lock != 1:
timestamp = time.time() + timeout + 1
cls._lock = cls.rdcon.setnx(cls.lock_key, timestamp)
# if 条件中,可能在运行到or之后被释放,也可能在and之后被释放
# 将导致 get到一个None,float失败。
if cls._lock == 1 or (
time.time() > cls.my_float(cls.rdcon.get(cls.lock_key)) and
time.time() > cls.my_float(cls.rdcon.getset(cls.lock_key, timestamp))):
break
else:
time.sleep(0.3)
@staticmethod
def release(cls):
if cls.rdcon.get(cls.lock_key) and time.time() < cls.rdcon.get(cls.lock_key):
cls.rdcon.delete(cls.lock_key)
def redis_lock_deco(cls):
def _deco(func):
def __deco(*args, **kwargs):
cls.get_lock(cls, args[1])
try:
return func(*args, **kwargs)
finally:
cls.release(cls)
return __deco
return _deco
@redis_lock_deco(RedisLock())
def my_func():
print "myfunc() called."
time.sleep(20)
if __name__ == "__main__":
my_func()
python redis分布式锁改进的更多相关文章
- Redis分布式锁
Redis分布式锁 分布式锁是许多环境中非常有用的原语,其中不同的进程必须以相互排斥的方式与共享资源一起运行. 有许多图书馆和博客文章描述了如何使用Redis实现DLM(分布式锁管理器),但是每个库都 ...
- Lua脚本在redis分布式锁场景的运用
目录 锁和分布式锁 锁是什么? 为什么需要锁? Java中的锁 分布式锁 redis 如何实现加锁 锁超时 retry redis 如何释放锁 不该释放的锁 通过Lua脚本实现锁释放 用redis做分 ...
- Redlock(redis分布式锁)原理分析
Redlock:全名叫做 Redis Distributed Lock;即使用redis实现的分布式锁: 使用场景:多个服务间保证同一时刻同一时间段内同一用户只能有一个请求(防止关键业务出现并发攻击) ...
- 分布式-技术专区-Redis分布式锁实现-第一步
承接前面一篇Redis分布式锁的原理介绍 https://www.cnblogs.com/liboware/p/11921759.html 我们针对于实现方案进行接下来上篇进行重新的规划和定义以及完善 ...
- Redis分布式锁的正确使用与实现原理
模拟一个电商里面下单减库存的场景. 1.首先在redis里加入商品库存数量. 2.新建一个Spring Boot项目,在pom里面引入相关的依赖. <dependency> <gro ...
- Why failover-based implementations are not enough Redis分布式锁实现 SET resource_name my_random_value NX PX 30000
核心 SET resource_name my_random_value NX PX 30000 Distributed locks with Redis – Redis https://redis. ...
- Redis 分布式锁|从青铜到钻石的五种演进方案
缓存系列文章: 缓存实战(一):20 图 |6 千字|缓存实战(上篇) 缓存实战(二):Redis 分布式锁|从青铜到钻石的五种演进方案 缓存实战(三):分布式锁中的王者方案 - Redisson 上 ...
- Redis 分布式锁使用不当,酿成一个重大事故,超卖了100瓶飞天茅台!!!(转)
基于Redis使用分布式锁在当今已经不是什么新鲜事了. 本篇文章主要是基于我们实际项目中因为redis分布式锁造成的事故分析及解决方案.我们项目中的抢购订单采用的是分布式锁来解决的,有一次,运营做了一 ...
- 利用redis分布式锁的功能来实现定时器的分布式
文章来源于我的 iteye blog http://ak478288.iteye.com/blog/1898190 以前为部门内部开发过一个定时器程序,这个定时器很简单,就是配置quartz,来实现定 ...
随机推荐
- SrpingBoot入门到入坟04-配置文件
SpringBoot使用一个全局的配置文件,名称是固定,作用就是修改SpringBoot自动配置的默认值. *application.properties *application.yml 先看看两者 ...
- python学习-15 基本数据类型4
1.range a = range(0 ,100 , 5) #创建>=0,<100的连续数字,步长为5 for b in a: print(b) 运算结果: 0 5 10 15 20 25 ...
- 利用Python进行数据分析_Pandas_数据清理、转换、合并、重塑
1 合并数据集 pandas.merge pandas.merge(left, right, how='inner', on=None, left_on=None, right_on=None, le ...
- centos7 通过yum安装mysql
但是CentOS7的yum源中默认好像是没有mysql的.为了解决这个问题,我们要先下载mysql的repo源. 1.下载mysql的repo源 $ wget http://repo.mysql.co ...
- Python笔记001-Python入门
第一章:Python入门 1.Python介绍 1.1 简介 Python是一种解释型,面向对象的语言.由吉多·范罗苏姆(Guido van Rossum)于1989年发明,1991年正式公布.官网: ...
- 基于laravel框架构建最小内容管理系统
校园失物招领平台开发 --基于laravel框架构建最小内容管理系统 摘要 针对目前大学校园人口密度大.人群活动频繁.师生学习生活等物品容易遗失的基本现状,在分析传统失物招领过程中的工作效率低下. ...
- Qt中容器类应该如何存储对象(最好使用对象指针类型,如:QList<TestObj*>,而不要使用 QList<TestObj> 这样的定义,建议采用 智能指针QSharedPointer)
Qt提供了丰富的容器类型,如:QList.QVector.QMap等等.详细的使用方法可以参考官方文档,网上也有很多示例文章,不过大部分文章的举例都是使用基础类型:如int.QString等.如果我们 ...
- 面试经典算法:快速排序Golang实现
Golang快速排序 定义 快速排序由C. A. R. Hoare在1962年提出.快速排序是对冒泡排序的一种改进,采用了一种分治的策略. 基本思想 通过一趟排序将要排序的数据分割成独立的两部分,其中 ...
- SOAP-1概述
简单对象访问协议 SOAP(简单对象访问协议)一般指简单对象访问协议 简单对象访问协议是交换数据的一种协议规范,是一种轻量的.简单的.基于XML(标准通用标记语言下的一个子集)的协议,它被设计成在WE ...
- 傅里叶变换通俗解释及快速傅里叶变换的python实现
通俗理解傅里叶变换,先看这篇文章傅里叶变换的通俗理解! 接下来便是使用python进行傅里叶FFT-频谱分析: 一.一些关键概念的引入 1.离散傅里叶变换(DFT) 离散傅里叶变换(discrete ...