Redis分布式锁实现

Redis分布式锁实现

在分布式环境下,利用Redis实现锁机制,避免资源竞争的做法非常常见。这里探讨一下Redis分布式
锁的实现方式、可能存在的问题以及适用场景。

setnx

最常见的方法是利用Redis指令setnx,只有不存在的情况下才赋值,执行完毕释放资源,然后删除锁。

> setnx lock true
(integer) 1
... 执行业务操作...
> del lock
(integer) 1

这种方法的问题在于假如获取锁成功的客户端一直不释放,例如客户端挂掉的情况下,会导致死锁问题。
解决方法是增加锁超时时间,避免长时间不释放。示例命令如下,expire_ttl替换为默认的超时时间。

> setnx lock true
(integer) 1
> expire lock expire_ttl
(integer) 1
... 执行业务操作...
> del lock
(integer) 1

但是问题又来了,setnx和expire是两条指令,不是一个原子操作,万一运气不好,客户端setnx指令执行
成功后立刻挂掉,又出现原来的死锁问题怎么办?
解决办法是改为一条指令,利用Redis 2.6.12版本以后对set指令新增的扩展参数实现相同功能。示例命
令如下:

> set lock true nx ex expire_ttl
OK
... 执行业务操作...
> del lock
(integer) 1

设置了超时时间确实解决了死锁问题,但是万一客户端执行业务操作的时间超过了,会不会导致其他问题?
例如:
1、客户端A获得锁,执行业务操作
2、锁超时释放
3、客户端B获得锁,执行业务操作
4、客户端A完成业务,释放锁
5、客户端C也可以获得锁了
在以上场景中,由于超时机制,使得A错误释放了B获得的锁,导致C也错误得获得了锁。
解决方法是获取锁时设置唯一的数值,然后释放时校验锁的数值师范匹配,而不是统一设置相同的值。
数值可以生成一个随机数,为了确保随机数唯一的概率,可以使用时间戳+一些变量作为为随机数种子,
或者概率要求高的情况下可以考虑使用UUID。释放时校验也需要先获取值判断,匹配再删除,需要多
条指令,这种情况下使用lua脚本执行,保证任务的原子性。示例命令如下,random_num替换为具体
的随机值。示例命令如下:

> set lock random_num nx ex expire_ttl
OK
... 执行业务操作...
> eval "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end" 1 lock random_num
(integer) 1

这种做法可以避免客户端A错误释放客户端B设置的锁,但是还是无法避免客户端B获得锁。怎么解决呢? 一种是释放失败客户端A业务回滚记录日志,另外一种就是客户端A启用一个守护进程对超时时间的续期, 从而防止在业务未执行完成时错误获得锁。另外守护进场续期次数应该有一定限制,避免长时间占用资 源。示例命令如下,random_num替换为具体的随机值,min_ttl替换为守护进程进行续期时要求的存活 最小时间,expire_ttl替换为默认的超时时间。 ```bash > set lock random_num nx ex 5 OK ... 启动守护进程定时续期... > eval "if redis.call('get', KEYS[1]) == ARGV[1] then if redis.call('ttl', KEYS[1]) < tonumber(ARGV[2]) then return redis.call('expire', KEYS[1], ARGV[3]) else return 1 end else return 0 end" 1 lock random_num min_ttl expire_ttl (integer) 1 ... 执行业务操作... > eval "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end" 1 lock random_num (integer) 1 ```

Redlock算法

setnx只适用于单机的Redis或者分布式环境下对锁一致性要求不高的场合,对于多台Redis组成的集群
或者主从,可能会出现问题。例如,在某台Redis获取锁成功,随后这台Redis就挂掉,导致锁状态没有
同步到其他主机,又或者客户端分别在不同的主机同时获得了锁,诸如此类的问题影响了锁的作用。

具体实现:5个以上隔离部署在不同物理机上的Master节点,使用相同的key和随机值向所有节点同时获
取锁,流程图如下:

posted on   yeyu456  阅读(340)  评论(0编辑  收藏  举报

编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示