redlock分布式锁真的安全吗

此文是对http://zhangtielei.com/posts/blog-redlock-reasoning-part2.html文章的个人归纳,如有问题请联系删除

什么是redlock

redlock是redis给出的分布式锁的实现规范

先说说基于单节点redis实现的分布式锁

SET resource_name random_value NX PX 30000 如果执行成功说明获取到锁了

random_value需要设置一个唯一标识避免冲突

resource_name 只有不存在的时候才能set成功 代表获取到了锁

px 30000 代表过期时间30秒

需要注意的是

1. 过期时间必须得设置 避免锁不能释放的情况

2. random_value还是很有必要的必须不重复 确保锁只能被锁的持有者删除

  举例:

  A获取锁 执行超过px时间 锁被释放

  B获取锁成功 执行

  A执行完释放锁 这时B是没有锁保护的

3. 释放锁必须要用lua脚本保证原子性

4. 在主从的情况下,A在master获取到锁 如果master宕机 并且 key还未同步到slave B从slave也可以获取到锁

由于第4点 单节点redis无法解决这个问题,所以才有了redlock

redlock算法获取锁的步骤

1. 记录当前时间

2. 按顺序依次向客户端申请锁,跟单节点申请锁一样只是多了一个超时时间用于redis节点不可用的情况(几十毫秒级别),获取锁失败立即向下一个客户端申请锁

3. 当前时间减去第一步获取的时间,如果n/2+1的节点获取锁成功,并且消耗时间未超过锁的有效时间,获取锁成功否则失败

4.重新计算锁的有效时间,有效时间减去第三步算出来的时间

5. 如果失败则向所有的redis节点发送lua删除锁操作 (避免redis加锁成功但是客户端未受到消息的情况)

虽然避免了failover但是 节点崩溃重启的时候仍然有安全性问题

1. A客户端锁住了 123节点 45没锁住

2. 此时3节点崩溃但是A客户端在上面加的锁未持久化

3. 3节点重启 B客户端锁住了 345 获取锁成功

解决方法有:

1. 延迟重启,节点崩溃了不立即重启,而是等到超过锁的失效时间之后再重启

依赖系统时钟导致的不安全性

1. A客户端在123节点获取锁成功

2.3节点时钟发生向前跳跃只是3节点上的锁过期

3.B客户端获取了345节点的锁

gc pause导致的不安全性

1. A客户端在接收到12345节点的成功获取锁之前 进行了gc pause超过了锁的有效时间

2. B客户端获取了123节点的锁

3. A节点恢复过来之后 拿到了成功的结果 认为自己获取锁成功了

注意:这个是在获取到成功信息之前 锁就过期了,以前是客户端获取到成功信息之后 锁才过期,破坏了锁服务本身的安全性 这个是不成立的对于redlock 因为redlock有一步是检查获取锁的时间是否超过锁的有效时间

zookeeper实现分布式锁

zookeeper的比redis功能多的地方是

创建/node之后 如果客户端长时间不能应答心跳 zookeeper会删除这个失联客户端创建的所有node节点 不用想redis一样考虑如何设置锁的过期时间

如果锁被A客户端持有,B客户端来申请锁失败,这时B客户端可以watch这个/node 当node锁被释放的时候 通知客户端B去获取锁 实现阻塞等待的功能

原文地址:https://www.cnblogs.com/isnotnull/p/14041374.html