基于Zookeeper实现分布式锁及Leader选举

基于Zookeeper实现分布式锁及Leader选举

分布式锁

先来看一个问题,如图所示,两个用户同时去抢购秒杀商品,当秒杀服务同时收到秒杀请求时,都去进行库存扣减,此时在没有做任何处理的情况下,就会导致库存数量变成负数从而导致超卖现象。

这种情况下我们一般会选择加锁的方式来避免并发的问题。但是在分布式场景中,采用传统的锁并不能解决跨进程并发的问题,所以需要引入一个分布式锁,来解决多个节点之间的访问控制。

image-20210828215542593

Zookeeper如何解决分布式锁

可以基于Zookeeper的两种特性来实现分布式锁,

先来说第一种,

使用唯一节点特性实现分布式锁

就是基于唯一节点特性,如图所示,多个应用程序去抢占锁资源时,只需要在指定节点上创建一个/Lock节点,由于Zookeeper中节点的唯一性特性,使得只会有一个用户成功创建/Lock节点,剩下没有创建成功的用户表示竞争锁失败。

image-20210828215657905

这种方法能达到目的,但是会有一个问题,如下图所示,假设有非常多的节点需要等待获得锁,那么等待的方式自然是使用Watcher机制来监听/lock节点的删除事件,一旦发现该节点被删除说明之前获得锁的节点已经释放了锁,此时剩下的B、C、D。节点同时会收到删除事件从而去竞争锁,这个过程会产生羊群效应。

image-20210828215745920

“羊群效应”,简单来说就是如果存在许多的客户端在等待获取锁,当成功获取到锁的进程释放该节点后,所有处于等待状态的客户端都会被唤醒,这个时候zookeeper在短时间内发送大量子节点变更事件给所有待获取锁的客户端,然后实际情况是只会有一个客户端获得锁。如果在集群规模比较大的情况下,会对zookeeper服务器的性能产生比较的影响。

使用有序节点实现分布式锁

因此为了解决这个问题,可以采用Zookeeper的有序节点特性来实现分布式锁。

如图所示,每个客户端都往指定的节点下注册一个临时有序节点,越早创建的节点,节点的顺序编号就越小,那么我们可以判断子节点中最小的节点设置为获得锁。如果自己的节点不是所有子节点中最小的,意味着还没有获得锁。这个的实现和前面单节点实现的差异性在于,每个节点只需要监听比自己小的节点,当比自己小的节点删除以后,客户端会收到watcher事件,此时再次判断自己的节点是不是所有子节点中最小的,如果是则获得锁,否则就不断重复这个过程,这样就不会导致羊群效应,因为每个客户端只需要监控一个节点。

image-20210828215923033

如图所示,表示有序节点实现分布式锁的流程。

image-20210828215958870

使用Zookeeper实现多个节点的leader选举

在分布式计算中,leader election是很重要的一个功能。

这个选举过程是这样子的:指派一个进程作为组织者,将任务分发给各节点。在任务开始前,哪个节点都不知道谁是leader或者coordinator。当选举算法开始执行后,每个节点最终会得到一个唯一的节点作为任务leader。除此之外,选举还经常会发生在leader意外宕机的情况下,新的leader要被选举出来,如图所示,这个就是所谓的leader选举,而zookeeper作为leader选举的功能,在很多中间件中都有使用,比如kafka基于zookeeper实现leader选举,Hadoop、Spark等。

image-20210828220218990

打赏

请我喝杯咖啡吧~

支付宝
微信