分布式锁

Redis分布式锁
 
使用setnx命令 加锁

 

代码解释 :
setnx 命令,意思就是 set if not exist,如果lockKey不存在了,把 key存入 Redis,保存成功后如果 result返回1,表示成功 ,如果非 1,表示失败。
expire(),设置过期时间,防止死锁,假设,如果一个锁 set后,一直不删掉,那这个锁相当于一直存在,产生死锁。
但是:
加锁 共分为两步,第一步 jedis.setnx,第二步 jedis.expire 设置过期时间 ,setnx与 expire不是一个原子操作,如果程序执行完第一步后异常了,第二步 jedis.expire(lockKey, expireTime) 没有得到执行,相当于这个锁没有 过期时间,有产生死锁的可能。
改进:

 

代码解释:
将加锁和设置过期时间 合二为一,原子操作。
 
Redis解锁:
使用 del命令解锁

 

代码解释:
通过 requestId判断加锁与解锁是不是同一个 客户端和 jedis.del(lockKey) 两步是不是原子操作,理论上 出现在执行完第一步 if 判断操作后锁其实已经过期了,并且被其它线程获取并加锁,这时执行 jedis.del(lockKey)操作,相当于把人家的锁释放了,这是不合理的。
改进:

 

代码解释:
通过 jedis客户端的 eval方法和 script脚本解决其中的原子问题。
 
 

 
Zookeeper 的分布式锁实现原理
 
一台机器接收到了请求之后,先获取 zookeeper上的一把分布式锁(zk会创建 一个znode),执行操作;然后另外一个机器也尝试去创建那个 znode,结果发现自己创建不了,因为被别人创建了,那只能等待,等待第一个机器执行完了方可 拿到锁。
使用Zookeeper的顺序节点特性,假如我们在 /lock/ 目录下创建了 3个节点,zk集群会按照发起创建的顺序来创建节点,节点分别为 /lock/00001, /lock/00002, /lock/00003,最后一位数字是依次递增的,节点名由 zk来完成。
ZK 中还有一种名为 临时节点的节点,临时节点由 某个 客户端创建,当客户端与ZK集群断开连接,则该节点自动被删除。
节点 分为 临时节点,临时顺序节点,持久化节点 ,持久化顺序节点
 

 
ZK 和 Redis 的区别,各自优缺点
 
Redis:
1. Redis 只能保证最终一致性,副本间的数据复制是异步进行(Set是写,Get是读,Redis集群一般是 读写分离架构,存在主从同步延迟情况),主从切换之后可能有部分数据没有复制过去可能会丢失锁情况,故强一致性要求的业务不推荐使用 Redis,推荐使用 zk。
2. Redis集群各方法的响应时间均为 最低。随着 并发量和业务量的提升其响应时间会有明显上升(公有集群 影响因素偏大),但是极限aps可以达到最大基本无异常。
 
Zookeeper:
1. 使用Zookeeper集群,锁 原理是使用 Zookeeper 的临时节点,临时节点的生命周期在 Client 与集群的 Session结束时结束。因此如果 某个Client节点存在网络问题,与Zookeeper集群断开连接,Session超时同样会导致锁被错误的释放(导致被 其它线程错误的持有),因此 Zookeeper也无法保证完全 一致。
2. Zookeeper 具有较好的稳定性;响应时间抖动很小,没有出现异常。但随着并发量和业务梳理的提升其响应时间和 QPS 会明显下降。

 

 
 
 
posted @ 2022-11-10 16:08  茄子777  阅读(76)  评论(0)    收藏  举报