暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

分布式锁的实现

唠叨一下 2021-10-28
257
分布式锁,本质上是选主问题,进一步而言,其实是共识问题(consensus),那么必然是遵从FLP理论的,即liveness和safeness不可兼得。所以,是选择不脑裂(brain split)还是选择高可用(high availability)呢?


用什么组件实现?
redis或者zookeeper,代表了liveness和safeness。或者说,代表了CAP理论中的A和C。
redis性能好,能抗住的qps高,但是其主从是异步的,很有可能在主节点上的锁信息即k-v还未同步到从节点,主节点就挂了。于是从节点被选为主节点后,就会导致脑裂问题。
zookeeper一致性做得好(这里有个误区,部分人认为zk是强一致性的即linearization consistency,其实不是的,zk只有write操作是强一致的,读只是causal consistency),所以不会出现脑裂问题,但是其写性能比较差,如果业务上频繁获取释放锁,则不行。一般来说,对于那种选主场景,可以用zk,因为选主的频率会很低。比如kafka的controller,HBase的master node等等。


更具体一点,如果采用redis实现分布式锁,需要注意什么?
  • 加锁,释放锁需要考虑原子性(并发问题中老生常谈了)

  • k-v怎么设计?唯一标识的业务和唯一标识的线程

  • 过期时间怎么设置?(没有完美解决方法)

这其实和分布式关系不大了,更偏向于concurrency一点。个人愚见,concurrency最需要考虑的就是原子性。

    

上面说到,redis异步导致容易出现脑裂问题。redis官方给出了解决方案[1],即redlock。具体不在此赘述。设计思路为:既然主从容易导致不一致,那么就不用主从结构;进一步,单点故障怎么解决呢?于是想到quorum(分布式中解决consensus的基本操作),即部署5个节点,只有在规定时间内获取到3个及以上节点上的锁,才算是获得锁了。具体分析还请参考ref。


说了这么多,真就万无一失了吗?

    必然不是!还记得上期挖的坑吗?fencing token或者说是zombie fencing。即当某个节点A已经获取了锁,但是其恰好锁快要过期时经历了一个long time gc,导致锁过期被下一任节点B获取,当B正在愉快的操作时,A垂死病中惊坐起,又开始操作。这不就又会造成脑裂问题吗?而上述中A的行为就是zombie,我们需要一个fencing来将该zombie屏蔽掉。

之前讨论的,是因为kv存储导致脑裂,zombie fencing则是因为client 节点导致的。
HBase曾经就发生过这种问题[2]。也是由于long time gc导致的,即region server gc,误被认为已经挂了,重新选主后,原先的server gc恢复回来后继续修改HDFS,造成数据不一致。

Reference:
[1] https://redis.io/topics/distlock
[2] ZooKeeper: Distributed Process Coordination



    

文章转载自唠叨一下,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论