分布式锁,本质上是选主问题,进一步而言,其实是共识问题(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实现分布式锁,需要注意什么?
这其实和分布式关系不大了,更偏向于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,造成数据不一致。[1] https://redis.io/topics/distlock[2] ZooKeeper: Distributed Process Coordination