redis和zk分布式锁

本文深入探讨了Redis和Zookeeper在实现分布式锁上的不同策略和优缺点。Redis通过setnx、setex命令及lua脚本解决死锁和原子性问题,但面临集群模式下锁丢失的风险;Zookeeper利用临时顺序节点特性,确保无死锁和过期问题,且在主从切换时能保持锁的一致性。两者各有优势,适用于不同的分布式场景。
摘要由CSDN通过智能技术生成

一、redis分布式锁

1.实现原理

版本一
用Redis的 setnx key value 命令 ,存在则返回0,不存在则添加key,返回1;相当于加锁
--
方法执行完 
finally {del key}

问题:如果方法中服务宕机,没有 del key, key永远存在,导致死锁
版本二:解决死锁
先setnx key value 命令创建锁
再用Redis中的expire key 10 设置过期时间,但是这俩加起来就不是原子操作
redis2.6.12 后支持参数
如新增 key 的过期时间 setex key time value  比如10秒
这俩命令要整合成一个原子性操作 set key value  ex nx  time 
ex :设置键的过期时间(单位秒)
nx :相当于setnx ,只有key不存在,才返回1
--
方法执行完 	
finally {del key}

问题:如果请求1时间过于长,使得key过期了还没执行完,请求2可以进来了,并且谁都可以随便删除key,使得锁和没有一样

请求1(需要15秒): 创建key1,10秒的时候key1过期,
请求2(需要8秒)进来,重新创建key2,执行了5秒后,请求1删除key2,
请求3(需要5秒)进来了,创建新的key3,3秒后,请求2删除key3,
请求4(需要5秒)进来创建key4,2秒后,请求3删除,key4......
版本三:增加uuid解决其它请求释放锁的问题,增加lua脚本解决删除原子性操作问题
为了防止锁被它人释放,需要创建一个唯一ID,标识为自己
给setex和del 加一个clintID(UUID),使得只能是自己删除自己的key,同时由于删除key时,也需要先get再del,这并不是一个原子操作,需要通过lua脚本实现
但是依然有请求1超长,key1自动过期,请求2进来的问题
版本四:解决锁过期时间不确定的问题
fork一个子线程(看门狗),定时(10秒),去检查主线程的key是否还持有key,如果持有就增加过期时间
但是实现比较麻烦
版本五:使用redisson客户端,解决上述问题

使用redisson框架,客户端

可重入锁
乐观锁
公平锁
读写锁
Redlock(红锁,下面会详细讲)
String lockKey ="key_001"
Rlock redissonLock = redisson.getLock(Lockkey);
//加锁
redissonLock.lock();
--
finally {
redissonLock.unlock();
}

就是我们上面的思路

2.怎么保证原子操作

一:加锁

二:lua脚本

if redis.call("get",KEYS[1]) == ARGV[1]
then
    return redis.call("del",KEYS[1])
else
    return 0
end

3.set命令

EX second :设置键的过期时间为 second 秒。 SET key value EX second 效果等同于 SETEX key second value 。
PX millisecond :设置键的过期时间为 millisecond 毫秒。 SET key value PX millisecond 效果等同于 PSETEX key millisecond value 。
NX :只在键不存在时,才对键进行设置操作。 SET key value NX 效果等同于 SETNX key value 。
XX :只在键已经存在时,才对键进行设置操作。

因为 SET 命令可以通过参数来实现和 SETNX 、 SETEX 和 PSETEX 三个命令的效果,所以将来的 Redis 版本可能会废弃并最终移除 SETNX 、 SETEX 和 PSETEX 这三个命令。

4.Redis分布式锁的缺点

之前解决的问题:

1. 死锁:设置过期时间
2. 过期时间评估不好,锁提前过期:守护线程,自动续期
3. 锁被别人释放:锁写入唯一标识,释放锁先检查标识,再释放

但是这些都是单机模式情况下,如果时集群情况下呢,发生主从复制呢

试想这样的场景!

1. 客户端 1 在主库上执行 SET 命令,加锁成功
2. 此时,主库异常宕机,SET 命令还未同步到从库上(主从复制是异步的)
3. 从库被哨兵提升为新主库,这个锁在新的主库上,丢失了!

二、zookeeper实现分布式锁

1.原理

zk一个功能就是临时顺序节点,当连接断开,节点删除,并且创建多次,节点号递增

1.客户端A创建节点my_lock , 创建节点成功xxx-00001,然后判断当前节点是不是my_lock下的第一个节点,是的,所以加锁成功

2.客户端B创建节点my_lock ,因为是有序的,所以节点是xxx-00002,然后判断当前节点是不是my_lock下的第一个节点,显然不是,对当前节点的上一个节点(xxx-00001)添加一个监听器

3.客户端A使用完后,释放锁,删除节点xxx-00001,ZK会负责通知监听这个节点的监听器,也就是客户端B的监听器说锁释放了。

4.客户端B开始加锁,重复上面的操作

2.优点

  • 没有死锁问题
  • 没有过期问题,当客户端连接断开,临时节点自动删除

参考文章:
https://zhuanlan.zhihu.com/p/150637733

https://zhuanlan.zhihu.com/p/425230130

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值