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

关于 redis 分布式锁的实现

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

    [分布式锁的实现文章][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  
       
    前面说错了,“ 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     Solana     1282 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 46ms UTC 17:15 PVG 01:15 LAX 09:15 JFK 12:15
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86