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

客户端使用 redis cluster 构建分布式锁

  •  
  •   jason0916 ·
    NoneGG · 2017-09-25 22:18:54 +08:00 · 5747 次点击
    这是一个创建于 2376 天前的主题,其中的信息可能已经有所发展或是发生改变。

    请各位大佬帮忙看看我的思路是不是有问题,如果能抛砖引玉得到更完善的思路那就更好了

    我目前的思路是:

    1. client 生成随机 token + 超时时间,用 setnx 获取锁

    2. 若获取成功则另外建立 readonly 的连接去读取锁所在的 master 节点对应的 slave 节点(假设有 N 个),检测是否同步锁同步成功(防止在同步前 master crash,slave 对外服务导致可以同时有两个 client 获取锁)当发现 N/2 + 1 的 slave 同步成功后停止检查返回成功

    3. 释放锁则使用 lua script 来做,只有在客户端 token 值等于锁当前值时才能释放锁(若持有锁的 client crash 了则等到超时自动释放),释放锁后同获取锁时一样检查 slave 内对应值是否还为 token 值,如果还为 token 值则认为锁没有释放成功

    14 条回复    2017-09-26 14:39:45 +08:00
    zhx1991
        1
    zhx1991  
       2017-09-25 22:27:32 +08:00
    没太懂啊

    都读主不就行了吗? 考虑从节点锁状态是否成功同步是做主会挂的准备吗?
    BBCCBB
        2
    BBCCBB  
       2017-09-25 22:28:36 +08:00
    直接看 redission 的实现思路, 或者 redis 作者的那个 redlock
    zhx1991
        3
    zhx1991  
       2017-09-25 22:29:13 +08:00
    这样依然是没法避免持有两把锁的

    redis 本身的设计理念, 对于 CAP 来说是既不满足 C 也不满足 A

    希望能有强一致的读写(锁永远不允许同时有两处获得)请用真正的 CP 系统比如 zk
    jason0916
        4
    jason0916  
    OP
       2017-09-25 22:42:44 +08:00
    @BBCCBB redisson 的话我简单看了下,可能有疏漏哈,貌似更多的是处理竞争这块,没怎么看到他对于主从模型的同步问题的解决,倒是跟 redis cluster 关系不大了。redlock 我有考虑过,这里对从节点的检查就是用的类似的思路(对于超时时间的处理还在考虑中)。主要是因为 redis cluster 里面没办法把一个 key hash 到不同的节点。而 redlock 算法更多的是给“由单点 redis 组成的集群”使用的,要求一个 key 可以 hash 到集群内不同的节点上。
    jason0916
        5
    jason0916  
    OP
       2017-09-25 22:44:11 +08:00
    @zhx1991 是这样的,这么设计主要就是为了防止主从间同步的问题。为什么依然没法避免持有两把锁啊?
    BBCCBB
        6
    BBCCBB  
       2017-09-25 23:34:12 +08:00
    redission 文档里第一部分就介绍了支持集群模式,主从模型,哨兵模式,可以深入研究
    orafy
        7
    orafy  
       2017-09-26 00:25:18 +08:00 via Android
    可以用 etcd 呀
    hand515
        8
    hand515  
       2017-09-26 08:12:59 +08:00
    对一致性有要求的,我建议 zookeeper 或 etcd。
    owt5008137
        9
    owt5008137  
       2017-09-26 08:42:39 +08:00 via Android
    @orafy @hand515 看应用场景吧,zookeeper 和 etcd 性能差 redis 一大截,而且除非自己做 sharded,扩容只提高可靠性,不增加性能。我觉得这些玩意还是只适合做服务间的管理,服务发现,进程管理,配置管理啊之类。并不适合高在线的业务。
    jason0916
        10
    jason0916  
    OP
       2017-09-26 11:13:46 +08:00
    @BBCCBB 嗯,我有看到他 wiki 里的配置,确实是支持 sentinel 和 cluster 的,所以研究他代码的时候就感觉很奇怪,貌似他的 redlock 的实现是由用户选择多个 key 来合并成一把锁,这样的话 key hash 的问题就交给用户去决定了,我就是对这一点抱有疑惑 [捂脸]
    jason0916
        11
    jason0916  
    OP
       2017-09-26 11:14:49 +08:00
    @orafy
    @hand515
    嗯,我也知道做这块最好不是用 redis cluster,主要是我自己做的一个客户端有同学提 issue 问有没有相关的支持,所以我才想实现看看
    jason0916
        12
    jason0916  
    OP
       2017-09-26 11:20:12 +08:00
    @owt5008137 etcd 我了解不多,不过 zk 的话因为有自带的逻辑时钟做 fencing,感觉一致性上比 redis 强一些。话说大佬你觉得我的实现方法可以用么?我想了几个场景目前想到可能出现的有两个问题,想听听你的看法。

    1. redlock 里面用于获取多个 master node 锁的时间消耗被算到了超时时间内,比如说超时设了 5s,获取用了 3s,那么超时就只剩 2s 了,这个应该在我这边应该算进超时时间么(我比较倾向于算进去,但是不肯定)
    2. 在较差的网络状况下是否应该 sleep 一段时间再去检查 slave node 以防止获取锁时同步延时过大导致所有客户端一直获取不到锁
    owt5008137
        13
    owt5008137  
       2017-09-26 14:11:33 +08:00 via Android
    @jason0916 我觉得思路上没什么问题。关于超时时间,我认为肯定是要算进去的呀,另外可以试试 value 里就记下超时时间。然后加容忍时间,如果有大于 N/2 的节点都成功后,检查超时时间是否在容忍值内,如果已经大于超时时间-容忍值了就视为加锁失败,然后加锁的时候也需要当前时间比原来的 value 的时间+容忍值大。一般内网的延迟大概都能估计出来吧。

    这个肯定没有 zk 或者 etcd 一致性强的,极端情况下会有锁已经过期,但是 client 认为没过期的情况。但是很容易性能完爆它。
    jason0916
        14
    jason0916  
    OP
       2017-09-26 14:39:45 +08:00
    @owt5008137 妥,谢谢大佬~
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   953 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 21:37 · PVG 05:37 · LAX 14:37 · JFK 17:37
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.