Zookeeper原理--分布式锁

原文网址:Zookeeper原理--分布式锁_IT利刃出鞘的博客-CSDN博客

简介

本文介绍用Zookeeper来实现分布式锁的方法和原理。

节点类型

让我们来回顾一下Zookeeper节点的概念: 

Zookeeper的数据存储结构就像一棵树,这棵树由节点组成,这种节点叫做Znode。Znode分为四种类型:

1.持久节点 (PERSISTENT)

默认的节点类型。创建节点的客户端与Zookeeper断开连接后,该节点依旧存在 。

2.持久顺序节点(PERSISTENT_SEQUENTIAL)

所谓顺序节点,就是在创建节点时,Zookeeper根据创建的时间顺序给该节点名称进行编号:

「每日分享」如何用Zookeeper实现分布式锁

 3.临时节点(EPHEMERAL)

和持久节点相反,当创建节点的客户端与zookeeper断开连接后,临时节点会被删除:

「每日分享」如何用Zookeeper实现分布式锁

「每日分享」如何用Zookeeper实现分布式锁

「每日分享」如何用Zookeeper实现分布式锁

4.临时顺序节点(EPHEMERAL_SEQUENTIAL)

顾名思义,临时顺序节点结合和临时节点和顺序节点的特点:在创建节点时,Zookeeper根据创建的时间顺序给该节点名称进行编号;当创建节点的客户端与zookeeper断开连接后,临时节点会被删除。

问题及解决方法

问题

解决方法

锁无法释放

Zookeeper可以有效的解决锁无法释放的问题,因为在创建锁的时候,客户端会在ZK中创建一个临时节点,一旦客户端获取到锁之后突然挂掉(Session连接断开),那么这个临时节点就会自动删除掉。其他客户端就可以再次获得锁。

非阻塞锁

Zookeeper可以实现阻塞的锁,客户端可以通过在ZK中创建顺序节点,并且在节点上绑定监听器,一旦节点有变化,Zookeeper会通知客户端,客户端可以检查自己创建的节点是不是当前所有节点中序号最小的,如果是,那么自己就获取到锁,便可以执行业务逻辑了。

不可重入

Zookeeper也可以有效的解决不可重入的问题,客户端在创建节点的时候,把当前客户端的主机信息和线程信息直接写入到节点中,下次想要获取锁的时候和当前最小的节点中的数据比对一下就可以了。如果和自己的信息一样,那么自己直接获取到锁,如果不一样就再创建一个临时的顺序节点,参与排队。

单点问题

Zookeeper可以有效的解决单点问题,ZK是集群部署的,只要集群中有半数以上的机器存活,就可以对外提供服务。

公平问题

Zookeeper可以解决公平锁问题,客户端在ZK中创建的临时节点是有序的,每次锁被释放时,ZK可以通知最小节点来获取锁,保证了公平。

一致性问题

Zookeeper是一个保证了弱一致性即最终一致性的分布式组件。

优点

  1. 有效解决这些问题:单点,不可重入,非阻塞、锁无法释放(不靠超时时间释放锁)。
  2. 实现简单。
  3. 可靠性高。

缺点

  1. 性能不如Redis

一致性

Zookeeper采用称为Quorum Based Protocol的数据同步协议。假如Zookeeper集群有N台Zookeeper服务器(N通常取奇数,3台能够满足数据可靠性同时有很高读写性能,5台在数据可靠性和读写性能方面平衡最好),那么用户的一个写操作,首先同步到N/2 + 1台服务器上,然后返回给用户,提示用户写成功。基于Quorum Based Protocol的数据同步协议决定了Zookeeper能够支持什么强度的一致性。

在分布式环境下,满足强一致性的数据储存基本不存在,它要求在更新一个节点的数据,需要同步更新所有的节点。这种同步策略出现在主从同步复制的数据库中。但是这种同步策略,对写性能的影响太大而很少见于实践。因为Zookeeper是同步写N/2+1个节点,还有N/2个节点没有同步更新,所以Zookeeper不是强一致性的。

用户的数据更新操作,不保证后续的读操作能够读到更新后的值,但是最终会呈现一致性。牺牲一致性,并不是完全不管数据的一致性,否则数据是混乱的,那么系统可用性再高分布式再好也没有了价值。牺牲一致性,只是不再要求关系型数据库中的强一致性,而是只要系统能达到最终一致性即可。

Zookeeper是否满足最终一致性,需要看客户端的编程方式

满足最终一致性编程的方法

  1. B进程监听Zookeeper上/z的数据变化
  2. A进程向Zookeeper的/z写入一个数据,成功返回前,Zookeeper需要调用注册在/z上的监听器,Leader将数据变化的通知告诉B
  3. B进程的事件响应方法得到响应后,去取变化的数据,那么B一定能够得到变化的值
  4. 这里的因果一致性提现在Leader和B之间的因果一致性,也就是是Leader通知了数据有变化

不满足最终一致性编程的方法

  1. A进程向Zookeeper的/z写入一个数据,成功返回
  2. A进程通知B进程,A已经修改了/z的数据
  3. B读取Zookeeper的/z的数据
  4. 由于B连接的Zookeeper的服务器有可能还没有得到A写入数据的更新,那么B将读不到A写入的数据

Zookeeper分布式锁的原理

Zookeeper分布式锁应用了临时顺序节点。具体如何实现呢?让我们来看一看详细步骤:

获取锁

首先,在Zookeeper当中创建一个持久节点ParentLock。当第一个客户端(Client1)想要获得锁时,需要在ParentLock这个节点下面创建一个临时顺序节点 Lock1。

「每日分享」如何用Zookeeper实现分布式锁

之后,Client1查找ParentLock下面所有的临时顺序节点并排序,判断自己所创建的节点Lock1是不是顺序最靠前的一个。如果是第一个节点,则成功获得锁。

「每日分享」如何用Zookeeper实现分布式锁

        

这时候,如果再有一个客户端 Client2 前来获取锁,则在ParentLock下载再创建一个临时顺序节点Lock2。

「每日分享」如何用Zookeeper实现分布式锁

Client2查找ParentLock下面所有的临时顺序节点并排序,判断自己所创建的节点Lock2是不是顺序最靠前的一个,结果发现节点Lock2并不是最小的。

于是,Client2向排序仅比它靠前的节点Lock1注册Watcher,用于监听Lock1节点是否存在。这意味着Client2抢锁失败,进入了等待状态。

「每日分享」如何用Zookeeper实现分布式锁

这时候,如果又有一个客户端Client3前来获取锁,则在ParentLock下载再创建一个临时顺序节点Lock3。

「每日分享」如何用Zookeeper实现分布式锁

Client3查找ParentLock下面所有的临时顺序节点并排序,判断自己所创建的节点Lock3是不是顺序最靠前的一个,结果同样发现节点Lock3并不是最靠前的。

于是,Client3向排序仅比它靠前的节点Lock2注册Watcher,用于监听Lock2节点是否存在。这意味着Client3同样抢锁失败,进入了等待状态。

「每日分享」如何用Zookeeper实现分布式锁

这样一来,Client1得到了锁,Client2监听了Lock1,Client3监听了Lock2。这恰恰形成了一个等待队列,很像是Java当中ReentrantLock所依赖的AQS。

锁的续期

相关网址

《从Paxos到Zookeeper 分布式一致性原理与实践》=> 7.4.3 会话管理=> 会话激活

为了保持客户端会话的有效性,在ZooKeeper的运行过程中,客户端会在会话超时时间过期范围内向服务端发送P1NG请求来保持会话的有效性,我们俗称“心跳检测”。同时,服务端需要不断地接收来自客户端的这个心跳检测,并且需要重新激活对应的客户端会话,我们将这个重新激活的过程称为TouchSession。会话激活的过程,不仅能够使服务端检测到对应客户端的存活性,同时也能让客户端自己保持连接状态。

图1 Leader服务器激活客户端会话流程
  1. 检验该会话是否已经被关闭。
    1. Leader会检査该会话是否已经被关闭,如果该会话已经被关闭,那么不再继续激活该会话。
  2. 计算该会话新的超时时间ExpirationTime_New。
    1. 如果该会话尚未关闭,那么就开始激活会话。
    2. 首先需要计算出该会话下一次超时时间点,使用的就是上面提到的计算公式。
  3. 定位该会话当前的区块。
    1. 获取该会话老的超时时间Expirati〇nTime_01d,并根据该超时时间来定位到其所在的区块。
  4. 迁移会话
    1. 将该会话从老的区块中取出,放入ExpirationTime_New对应的新区块中 ,如图2所示
图2 会话迁移

通过以上4步,就基本完成会话激活的过程。

在上面的会话激活过程中,我们可以看到,只要客户端发来心跳检测,那么服务端就会进行一次会话激活。心跳检测由客户端主动发起,以PING请求的形式向服务端发送。但实际上,在ZooKeeper服务端的设计中,只要客户端有请求发送到服务端,那么就会触发一次会话激活。因此,总的来讲,大体会出现以下两种情况下的会话激活。

  1. 只要客户端向服务端发送请求,包括读或写请求,那么就会触发一次会话激活。
  2. 如果客户端发现在sessionTimeout/3时间内尚未和服务器进行过任何通信,即没有向服务端发送任何请求,那么就会主动发起一个PING请求,服务端收到该请求后,就会触发上述第一种情况下的会话激活。

释放锁

释放锁分为两种情况:

1.任务完成,客户端显示释放

当任务完成时,Client1会显示调用删除节点Lock1的指令。

「每日分享」如何用Zookeeper实现分布式锁

2.任务执行过程中,客户端崩溃

获得锁的Client1在任务执行过程中,如果崩溃,则会断开与Zookeeper服务端的链接。根据临时节点的特性,相关联的节点Lock1会随之自动删除。

「每日分享」如何用Zookeeper实现分布式锁

由于Client2一直监听着Lock1的存在状态,当Lock1节点被删除,Client2会立刻收到通知。这时候Client2会再次查询ParentLock下面的所有节点,确认自己创建的节点Lock2是不是目前最小的节点。如果是最小,则Client2顺理成章获得了锁。

「每日分享」如何用Zookeeper实现分布式锁

同理,如果Client2也因为任务完成或者节点崩溃而删除了节点Lock2,那么Client3就会接到通知。

「每日分享」如何用Zookeeper实现分布式锁

最终,Client3成功得到了锁。

问答

获得了锁的JVM,一直不释放锁如何处理

可以控制续命的次数,如果续命多次还是没有释放锁的话,则会超时自动释放锁,并且回滚当前事务的操作。

其他网址

《从Paxos到Zookeeper 分布式一致性原理与实践》=> 4.1.3 ZooKeeper的基本概念

  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
### 回答1: Zookeeper分布式锁原理是利用Zookeeper的节点唯一性和监听机制实现的。当多个客户端同时请求锁时,Zookeeper会创建一个临时有序节点,节点的名称是按照一定规则生成的,同时客户端会监听自己前一个节点的变化情况。当前一个节点被删除时,代表锁已经被释放,当前客户端就可以获取锁。如果当前客户端没有获取到锁,则会监听自己前一个节点的变化情况,直到获取到锁为止。这样就可以保证在分布式环境下,同一时刻只有一个客户端能够获取到锁,从而实现分布式锁的功能。 ### 回答2: Zookeeper是一个分布式协调服务,可用于在分布式系统中实现分布式锁。它的原理如下: 1. 创建锁节点:当一个客户端想要获取一个分布式锁时,它会在Zookeeper的目录树上创建一个临时有序节点,并在节点路径中包含一个唯一的标识符。比如,客户端创建了一个名为“/lock”的节点,Zookeeper会自动将其命名为“/lock000000001”。 2. 获取锁:客户端会尝试获取锁,即查找目录中排在它前面的节点。如果当前客户端创建的节点是目录中最小的节点(即没有其他节点在它前面),则认为它获取到了锁。 3. 监听节点:如果客户端没有获取到锁,它会对前一个节点(即比它小的最大节点)进行监听。一旦该节点被删除(即表示上一个客户端释放了锁),Zookeeper会通知当前客户端。 4. 释放锁:客户端在使用完锁之后,会删除自己创建的节点。这样,下一个节点的客户端就可以尝试获取锁。 通过上述原理Zookeeper实现了分布式锁的功能。它是基于临时有序节点的创建和监听实现的,可以保证在分布式环境下的锁的唯一性和互斥性。同时,Zookeeper还能够提供高可用性和可靠性,因为它是一个高性能的分布式协调服务,能够处理大规模分布式系统的复杂场景。 ### 回答3: Zookeeper是一个开源的分布式协调服务,可以提供高可用的服务注册与发现、配置管理、分布式锁等功能。其中,分布式锁Zookeeper的重要特性之一。 Zookeeper分布式锁实现原理主要涉及四个步骤: 1. 创建唯一节点:使用Zookeeper提供的API,在指定路径下创建一个唯一的临时顺序节点。每个要竞争锁的进程都会按顺序创建自己的节点。 2. 检查最小节点:通过获取指定路径下所有子节点,并将节点按顺序排序,判断自己创建的节点是否是最小节点。如果是最小节点,则表示该进程获取到了锁。 3. 监听前一个节点:如果自己创建的节点不是最小节点,则需要监听自己创建节点的前一个节点。一旦该节点被删除,表明前一个节点释放了锁,此时进程重新执行第二步来判断自己是否可以获取到锁。 4. 释放锁:当进程完成了自身的任务后,需要调用Zookeeper提供的API删除自己创建的节点,即释放锁,以便其他进程能够继续竞争获取锁的机会。 通过以上的步骤,Zookeeper实现了基于节点顺序的分布式锁机制。它能够确保同一时间只有一个进程能够获取到锁,从而实现了对共享资源的互斥访问。此外,Zookeeper还通过监听机制实现了高效的锁释放,避免了不必要的资源浪费和竞争。 需要注意的是,Zookeeper分布式锁的实现需要保证Zookeeper集群的高可用性和稳定性。只有当Zookeeper集群正常工作时,才能保证分布式锁的正确性和可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT利刃出鞘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值