一 基于redis的分布式锁
setnx 方式设置值;从而加锁;
- 解锁时,为了保证原子性(查询锁,判断值并删除),需要在redis服务端用脚本来实现查询并删除;
- 缺点是:如果master和slave结构,如果存在脑裂或者数据丢失情况,导致锁的数据没有同步,就导致了分布式锁的失效。
补救方案是官方推荐的redlock方案:
给每个master都尽量上锁,上锁数量是(总节点数/2+1),就认为上锁成功,比如5个节点就要3个都上锁才算成功。
获取锁时,当在3个(超过半数)redis上请求到锁的时候,才算是真正获取到了锁。如果没有获取到锁,则把部分已锁的redis释放掉。
二 基于zk的分布式锁
- 临时节点方式
上锁就是添加临时节点,解锁就是临时节点删除;
其他线程上锁,发现添加临时节点失败,就添加一个zk节点监听器并阻塞当前线程。当节点被删除时,触发监听器,于是当前线程会继续尝试加锁,如果添加临时节点成功,则加锁成功,如果添加失败,则说明竞争锁失败,只能继续添加节点监听器,重复循环。
- 临时顺序节点方式
需要加锁的线程都依次在zk上添加临时顺序节点,zk会按照顺序从小到大依次选取节点,所被选取到的节点,即认为是获取锁的线程。(可以监听顺序比自己小1的节点,只要前一个节点删除了,就触发监听,监听内部就可以实现判断当前节点是不是最小节点,是的话就等同于获取到锁)
三 redis和zk的分布式锁的比较
- redis 需要轮询,而zk是主动通知,因此zk效率更高;
- redis 创建锁的客户端如果挂了,只能等待超时后解锁;而zk在客户端挂了后就会自动释放锁;
- redis 需要做值判断,写脚本等,而且redlock也会存在多节点数据问题,比较麻烦;zk的语义简单明了。
网友评论