zookeeper 分布式锁原理(分布式锁实现原理)

2022-07-28 17:06:41 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

Zookeeper分布式锁的原理

问:在什么样的场景下我们需要使用Zookeeper分布式锁呢?

在分布式的项目中,指定的项目我们需要使用到锁的机制,但是在分布式下我们使用的内存锁都是相对独立的,因为每一个项目都有一个自己的JVM,而我们使用java类的锁都是受JVM控制的,这样在两台真实服务器上调用同一把锁的时候是没有办法进行锁操作,这个是我们就需要用到Zookeeper分布式锁了。

问:什么是Zookeeper分布式锁的节点zndoe?

这里我们在处理业务时候统一使用Zookeeper的锁,我们需要在调用Zookeeper锁之前创建一个节点命名空间(节点称为znode),每个节点都用一个以斜杠(/)分隔的路径表示,而且每个节点都有父节点(根节点除外),非常类似于文件系统。例如,/foo/mylock这个表示一个znode,它的父节点为/foo,父父节点为/,而/为根节点没有父节点。与文件系统不同的是,这些节点都可以设置关联的数据,而文件系统中只有文件节点可以存放数据而目录节点不行。Zookeeper为了保证高吞吐和低延迟,在内存中维护了这个树状的目录结构,这种特性使得Zookeeper不能用于存放大量的数据,每个节点的存放数据上限为1M。

如图:

问:Zookeeper分布式锁是如何保证高可用的?

为了保证高可用,zookeeper需要以集群形态来部署,集群的数量一定要为奇数,因为Zookeeper的选举机制集群的数量不能为偶数。这样只要集群中大部分机器是可用的(能够容忍一定的机器故障),那么zookeeper本身仍然是可用的。客户端在使用zookeeper时,需要知道集群机器列表,通过与集群中的某一台机器建立TCP连接来使用服务,客户端使用这个TCP链接来发送请求、获取结果、获取监听事件以及发送心跳包。如果这个连接异常断开了,客户端可以连接到另外的机器上。

客户端的读请求可以被集群中的任意一台机器处理,如果读请求在节点上注册了监听器,这个监听器也是由所连接的zookeeper机器来处理。对于写请求,这些请求会同时发给其他zookeeper机器其他机器会转发给leader由leader统一操作写操作,leader完成后请求才会返回成功。

因此,随着zookeeper的集群机器增多,读请求的吞吐会提高但是写请求的吞吐会下降。有序性zookeeper中非常重要的一个特性,所有的更新都是全局有序的,每个更新都有一个唯一的时间戳,这个时间戳称为zxid(Zookeeper Transaction Id)。而读请求只会相对于更新有序,也就是读请求的返回结果中会带有这个zookeeper最新的zxid。

问:Zookeeper如何实现分布式锁的?

在描述算法流程之前,先看下zookeeper中几个关于节点的有趣的性质:

有序节点:假如当前有一个父节点为/lock,我们可以在这个父节点下面创建子节点;zookeeper提供了一个可选的有序特性,例如我们可以创建子节点“/lock/node-”并且指明有序,那么zookeeper在生成子节点时会根据当前的子节点数量自动添加整数序号,也就是说如果是第一个创建的子节点,那么生成的子节点为/lock/node-0000000000,下一个节点则为/lock/node-0000000001,在下一个节点是/lock/node-0000000002,依次类推。

临时节点:客户端可以建立一个临时节点,在会话结束或者会话超时后,zookeeper会自动删除该节点。

事件监听:在读取数据时,我们可以同时对节点设置事件监听,当节点数据或结构变化时,zookeeper会通知客户端。当前zookeeper有如下四种事件:1)节点创建;2)节点删除;3)节点数据修改;4)子节点变更。

下面描述使用zookeeper实现分布式锁的算法流程,假设锁空间的根节点为/lock:

1.客户端连接zookeeper,并在/lock下创建临时的且有序的子节点,第一个客户端对应的子节点为/lock/lock-0000000000,第二个为/lock/lock-0000000001,以此类推。

2.客户端获取/lock下的子节点列表,判断自己创建的子节点是否为当前子节点列表中序号最小的子节点,如果是则认为获得锁,否则监听/lock的子节点变更消息,获得子节点变更通知后重复此步骤直至获得锁;

3.执行业务代码;

4.完成业务流程后,删除对应的子节点释放锁。

注意:步骤1中创建的临时节点能够保证在故障的情况下锁也能被释放,考虑这么个场景:假如客户端a当前创建的子节点为序号最小的节点,获得锁之后客户端所在机器宕机了,客户端没有主动删除子节点;如果创建的是永久的节点,那么这个锁永远不会释放,导致死锁;由于创建的是临时节点,客户端宕机后,过了一定时间zookeeper没有收到客户端的心跳包判断会话失效,将临时节点删除从而释放锁。

业务流程如图:

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/128538.html原文链接:https://javaforall.cn

0 人点赞