0X01 python redis分布式锁通用方法

REDIS分布式锁实现的方式:SETNX + GETSET

使用Redis SETNX 命令实现分布式锁

python 版本实现上述思路(案例1)

Redis分布式锁的python实现

但是,流通的代码 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分布式锁改进的更多相关文章

  1. Redis分布式锁

    Redis分布式锁 分布式锁是许多环境中非常有用的原语,其中不同的进程必须以相互排斥的方式与共享资源一起运行. 有许多图书馆和博客文章描述了如何使用Redis实现DLM(分布式锁管理器),但是每个库都 ...

  2. Lua脚本在redis分布式锁场景的运用

    目录 锁和分布式锁 锁是什么? 为什么需要锁? Java中的锁 分布式锁 redis 如何实现加锁 锁超时 retry redis 如何释放锁 不该释放的锁 通过Lua脚本实现锁释放 用redis做分 ...

  3. Redlock(redis分布式锁)原理分析

    Redlock:全名叫做 Redis Distributed Lock;即使用redis实现的分布式锁: 使用场景:多个服务间保证同一时刻同一时间段内同一用户只能有一个请求(防止关键业务出现并发攻击) ...

  4. 分布式-技术专区-Redis分布式锁实现-第一步

    承接前面一篇Redis分布式锁的原理介绍 https://www.cnblogs.com/liboware/p/11921759.html 我们针对于实现方案进行接下来上篇进行重新的规划和定义以及完善 ...

  5. Redis分布式锁的正确使用与实现原理

    模拟一个电商里面下单减库存的场景. 1.首先在redis里加入商品库存数量. 2.新建一个Spring Boot项目,在pom里面引入相关的依赖. <dependency> <gro ...

  6. 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. ...

  7. Redis 分布式锁|从青铜到钻石的五种演进方案

    缓存系列文章: 缓存实战(一):20 图 |6 千字|缓存实战(上篇) 缓存实战(二):Redis 分布式锁|从青铜到钻石的五种演进方案 缓存实战(三):分布式锁中的王者方案 - Redisson 上 ...

  8. Redis 分布式锁使用不当,酿成一个重大事故,超卖了100瓶飞天茅台!!!(转)

    基于Redis使用分布式锁在当今已经不是什么新鲜事了. 本篇文章主要是基于我们实际项目中因为redis分布式锁造成的事故分析及解决方案.我们项目中的抢购订单采用的是分布式锁来解决的,有一次,运营做了一 ...

  9. 利用redis分布式锁的功能来实现定时器的分布式

    文章来源于我的 iteye blog http://ak478288.iteye.com/blog/1898190 以前为部门内部开发过一个定时器程序,这个定时器很简单,就是配置quartz,来实现定 ...

随机推荐

  1. [转帖]使用TOAD优化复杂SQL

    独家秘笈!看下如何一键优化Oracle数据库复杂sql,DBA必备 https://www.toutiao.com/i6741208493644055053/ 原来toad 还有这种功能 感觉类似于 ...

  2. Navicat 导入,导出数据 etc

    Navicat 不仅做了分页查询, 显示 `SELECT *,rowid "NAVICAT_ROWID" FROM "main"."Table_100 ...

  3. c函数模板实现

    实现冒泡排序模板 #include <stdio.h> #include <stdlib.h> #include <time.h> #include <str ...

  4. GBDT笔记

    GBDT笔记 GBDT是Boosting算法的一种,谈起提升算法我们熟悉的是Adaboost,它和AdaBoost算法不同: 区别如下: AdaBoost算法是利用前一轮的弱学习器的误差来更新样本权重 ...

  5. Git拉取代码切换分支

    1.克隆代码 cd d:/GitTest //指定存放的目录 git clone https://git.oschina.net/name/test.git //你的仓库地址 2.查看远程所有分支 g ...

  6. Mybatis-Plus myBatis的增强工具

    1. Mybatis-Plus简介 1.1. 什么是Mybatis-Plus MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为 ...

  7. Nginx学习笔记(一):Nginx 进程模型 / 事件处理模型

    Nginx 进程模型 ​​​​ 多进程模型 进程间相互独立,无需加锁,且互不影响: 一个进程退出了不影响其他的进程运行,降低风险: 当请求到来,多个 worker 通过竞争 accrpt_mutex ...

  8. delete删除数据造成归档日志增加,操作系统空间不足导致数据库hang住

    业务需求,对日志表历史数据进行清理.历史表均很大,使用delete 操作删除90天前的数据. 第一部分:快速删除数据 SQL> alter table CC.F_LOG parallel ; S ...

  9. C# DataTable和List转换操作类

    using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.R ...

  10. (十四)角色管理(Ztree插件的基本使用)

    1. 建表 角色表 菜单表 角色-菜单(这个表中的role_id和menuu_id都不能被设置为主键,否则当插入一个新角色的时候,一个角色可能拥有多个菜单(role_id重复),一个菜单可能被多个角色 ...