关于 redis 分布式锁的实现

2016-08-02 17:31:01 +08:00
 twogoods

[分布式锁的实现文章][1],单点的方式很好理解,但在 redis 集群上会出现问题,如:

  1. 客户端 A 在主节点获得了一个锁。
  2. 主节点挂了,而到从节点的写同步还没完成。
  3. 从节点被提升为主节点。
  4. 客户端 B 获得和 A 相同的锁

文中描述了 redlock 算法, 获取锁的步奏

  1. 获取当前时间,以毫秒为单位。
  2. 以串行的方式尝试从所有的 N 个实例中获取锁,使用的是相同的 key 值和相同的随机 value 值。在从每个实例获取锁时,客户端会设置一个连接超时,其时长相比锁的自动释放时间要短得多。例如,若锁的自动释放时间是 10 秒,那么连接超时大概设在 5 到 50 毫秒之间。这可以避免当 Redis 节点挂掉时,会长时间堵住客户端:如果某个节点没及时响应,就应该尽快转到下个节点。
  3. 客户端计算获取所有锁耗费的时长,方法是使用当前时间减去步骤 1 中的时间戳。当且仅当客户端能从多数节点(至少 3 个)中获得锁,并且耗费的时长小于锁的有效期时,可认为锁已经获得了。
  4. 如果锁获得了,它的最终有效时长将重新计算为其原时长减去步骤 3 中获取锁耗费的时长。
  5. 如果锁获取失败了(要么是没有锁住 N/2+1 个节点,要么是锁的最终有效时长为负数),客户端会对所有实例进行解锁操作(即使对那些没有加锁成功的实例也一样)。

我不是很理解这个算法,假设一个 3 主 3 从的 redis 集群,从描述中看是setnx这个操作要在 6/2+1=4 个节点上操作成功,才认为是获得了锁。在客户端操作 redis 集群的时候可以直接操作到某一节点吗?以上是猜测,可能一开始就错了,有人能指点一下吗? [1]: http://www.oschina.net/translate/redis-distlock

5598 次点击
所在节点    Redis
7 条回复
Numbcoder
2016-08-02 17:51:40 +08:00
对可用性要求这么高的分布式锁,还是建议用 ZooKeeper Etcd Consul 这些
Redis 虽然也能做,但是你这种极端情况下还是不可靠
zhx1991
2016-08-02 19:33:23 +08:00
@Numbcoder zk 大量写会瞎吧
serial
2016-08-02 22:04:20 +08:00
集群也没有什么大的改变,仅仅是为了故障转移,锁还是单点逻辑。 master 会和 slave 同步 锁状态而已。
serial
2016-08-02 22:04:59 +08:00
主要改变内容,都是 master 故障转移和锁在 slave 同步。
twogoods
2016-08-03 00:09:14 +08:00
@serial 没理解, master 挂了来不及同步到 slave
serial
2016-08-03 08:47:58 +08:00
前面说错了,“ master 会和 slave 同步锁状态”。

就我的理解,他这是使用多数投票的方式。假设有 5 台 redis ,每台限定取锁时间 30ms 。每个请求取锁的时候,挨个访问 5 台 redis ,至少 3 台能获得锁,则认为取锁成功。取锁总时间超过 30ms * 3 也被认为是失败。拥有锁的时间假设是 1 s ,那么实际可拥有锁的时间 = 1s - 取锁花费的时间。
marffin
2016-08-03 11:29:22 +08:00
刚好昨天看了一下 Redlock 以及相关的文章,楼主应该直接去看一下 Redlock 的 Github 主页最后提及的三篇文章。总结一下就是 Redlock 有点高炮打蚊子的感觉,而且还打偏了。过于复杂,但是由于没有给锁加上版本,所以在分布式的情况下仍然有缺陷。解决的办法有三种:
1. 用单机版,单一 redis instance ,不存在分布式
2. 给锁加上单向递增的版本,如果客户端尝试用旧版本的锁写入则应该拒绝
3. 用 zookeeper 等成熟的分布式锁

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/296619

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX