V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
twogoods
V2EX  ›  Redis

关于 redis 分布式锁的实现

  •  
  •   twogoods · 2016-08-02 17:31:01 +08:00 · 5603 次点击
    这是一个创建于 3053 天前的主题,其中的信息可能已经有所发展或是发生改变。

    [分布式锁的实现文章][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

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

    就我的理解,他这是使用多数投票的方式。假设有 5 台 redis ,每台限定取锁时间 30ms 。每个请求取锁的时候,挨个访问 5 台 redis ,至少 3 台能获得锁,则认为取锁成功。取锁总时间超过 30ms * 3 也被认为是失败。拥有锁的时间假设是 1 s ,那么实际可拥有锁的时间 = 1s - 取锁花费的时间。
    marffin
        7
    marffin  
       2016-08-03 11:29:22 +08:00
    刚好昨天看了一下 Redlock 以及相关的文章,楼主应该直接去看一下 Redlock 的 Github 主页最后提及的三篇文章。总结一下就是 Redlock 有点高炮打蚊子的感觉,而且还打偏了。过于复杂,但是由于没有给锁加上版本,所以在分布式的情况下仍然有缺陷。解决的办法有三种:
    1. 用单机版,单一 redis instance ,不存在分布式
    2. 给锁加上单向递增的版本,如果客户端尝试用旧版本的锁写入则应该拒绝
    3. 用 zookeeper 等成熟的分布式锁
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5562 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 02:26 · PVG 10:26 · LAX 18:26 · JFK 21:26
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.