由于资料内容太多,平台篇幅限制,小编就展现了以上部分面试专题与资料,如需获取以下全部面试资料,可以【点击这里】,可复制链接后用石墨文档 App 或小程序打开获取。
ZooKeeper 是一个分布式的,开放源码的分布式应用程序协调服务,是 Google 的 Chubby
一个开源的实现,它是集群的管理者,监视着集群中各个节点的状态根据节点提交的反馈进行下一步合理操作。最终,将简单易用的接口和性能高效、功能稳定的系统提供给用户。
客户端的读请求可以被集群中的任意一台机器处理,如果读请求在节点上注册了监听器,这个监听器也是由所连接的 zookeeper 机器来处理。对于写请求,这些请求会同时发给其他 zookeeper 机器并且达成一致后,请求才会返回成功。因此,随着 zookeeper 的集群机器增多,读请求的吞吐会提高但是写请求的吞吐会下降。有序性是 zookeeper 中非常重要的一个特性,所有的更新都是全局有序的,每个更新都有一个唯一的时间戳,这个时间戳称为 zxid(Zookeeper Transaction Id)
。而读请求只会相对于更新有序,也就是读请求的返回结果中会带有这个 zookeeper
最新的 zxid
。
PERSISTENT
-持久化目录节点zookeeper
断开连接后,该节点依旧存在PERSISTENT_SEQUENTIAL
-持久化顺序编号目录节点EPHEMERAL
-临时目录节点EPHEMERAL_SEQUENTIAL
-临时顺序编号目录节点所谓集群管理无在乎两点:是否有机器退出和加入、选举 master。
对于第一点,所有机器约定在父目录下创建临时目录节点,然后监听父目录节点的子节点变化消息。一旦有机器挂掉,该机器与 zookeeper 的连接断开,其所创建的临时目录节点被删除,所有其他机器都收到通知:某个兄弟目录被删除,于是,所有人都知道:它上船了。
新机器加入也是类似,所有机器收到通知:新兄弟目录加入,highcount
又有了,对于第二点,我们稍微改变一下,所有机器创建临时顺序编号目录节点,每次选取编号最小的机器作为 master
就好。
在获取分布式锁的时候在 locker 节点 下创建临时顺序节点,释放锁的时候删除该临时节点。客户端调用 createNode 方法 在 locker
下创建临时顺序节点,然后调用 getChildren(“locker”)
来获取 locker
下面的所有子节点,注意此时不用设置任何 Watcher
。客户端获取到所有的子节点 path
之后,如果发现自己创建的节点在所有创建的子节点序号最小,那么就认为该客户端获取到了锁。如果发现自己创建的节点并非 locker
所有子节点中最小的,说明自己还没有获取到锁,此时客户端需要找到比自己小的那个节点,然后对其调用 exist()方法
,同时对其注册事件监听器。之后,让这个被关注的节点删除,则客户端的 Watcher
会收到相应通知,此时再次判断自己创建的节点是否是 locker 子节点
中序号最小的,如果是则获取到了锁,如果不是则重复以上步骤继续获取到比自己小的一个节点并注册监听。当前这个过程中还需要许多的逻辑判断。
代码的实现主要是基于互斥锁,获取分布式锁的重点逻辑在于 BaseDistributedLock
,实现了基于 Zookeeper 实现分布式锁的细节。
两种类型的队列:
FIFO
方式进行入队和出队操作。第一类,在约定目录下创建临时目录节点,监听节点数目是否是我们要求的数目。
第二类,和分布式锁服务中的控制时序场景基本原理一致,入列有编号,出列按编号。在特定的目录下创建 PERSISTENT_SEQUENTIAL 节点
,创建成功时 Watcher
通知等待的队列,队列删除序列号最小的节点用以消费。此场景下 Zookeeper 的 znode
用于消息存储,znode
存储的数据就是消息队列中的消息内容,SEQUENTIAL 序列号
就是消息的编号,按序取出即可。由于创建的节点是持久化的,所以不必担心队列消息的丢失问题。
Zookeeper 作为一个集群提供一致的数据服务,自然,它要在所有机器间做数据复制。数据复制的好处:
从客户端读写访问的透明度来看,数据复制集群系统分下面两种:
对 zookeeper 来说,它采用的方式是写任意。通过增加机器,它的读吞吐能力和响应能力扩展性非常好,而写,随着机器的增多吞吐能力肯定下降(这也是它建立 observer
的原因),而响应能力则取决于具体实现方式,是延迟复制保持最终一致性,还是立即复制快速响应。
每个 Server
在工作过程中有三种状态:
Zookeeper 本身也是集群,推荐配置不少于 3 个服务器。Zookeeper 自身也要保证当一个节点宕机时,其他节点会继续提供服务。
如果是一个 Follower
宕机,还有 2 台服务器提供访问,因为 Zookeeper 上的数据是有多个副本的,数据并不会丢失;
如果是一个 Leader
宕机,Zookeeper 会选举出新的 Leader
。
ZK 集群的机制是**只要超过半数的节点正常,集群就能正常提供服务。**只有在 ZK 节点挂得太多,只剩一半或不到一半节点能工作,集群才失效。
所以
3 个节点的 cluster
可以挂掉 1 个节点(leader 可以得到 2 票>1.5)
2 个节点的 cluster
就不能挂掉任何 1 个节点了(leader 可以得到 1 票<=1)
Watch 机制官方声明:一个 Watch 事件是一个一次性的触发器,当被设置了 Watch 的数据发生了改变的时候,则服务器将这个改变发送给设置了 Watch 的客户端,以便通知它们。
Zookeeper 机制的特点:
watcher event
会被发送到 client
,但是 client
只会收到一次这样的信息。watcher event
异步发送 watcher
的通知事件从 server
发送到 client
是异步的,这就存在一个问题,不同的客户端和服务器之间通过 socket
进行通信,由于网络延迟或其他因素导致客户端在不通的时刻监听到事件,由于 Zookeeper 本身提供了 ordering guarantee
,即客户端监听事件后,才会感知它所监视 znode
发生了变化。所以我们使用 Zookeeper 不能期望能够监控到节点每次的变化。Zookeeper 只能保证最终的一致性,而无法保证强一致性。getdata() and exists()
设置数据监视,getchildren()
设置了子节点监视。watcher getData
、exists
、getChildren
watcher create
、delete
、setData
setData()
会触发 znode
上设置的 data watch
(如果 set 成功的话)。一个成功的 create()
操作会触发被创建的 znode
上的数据 watch
,以及其父节点上的 child watch
。而一个成功的 delete()
操作将会同时触发一个 znode
的 data watch
和 child watch
(因为这样就没有子节点了),同时也会触发其父节点的 child watch
。watch
将会被以任意会话事件触发。当与一个服务器失去连接的时候,是无法接收到 watch
的。而当 client
重新连接时,如果需要的话,所有先前注册过的 watch
,都会被重新注册。通常这是完全透明的。只有在一个特殊情况下,watch
可能会丢失:对于一个未创建的 znode
的 exist watch
,如果在客户端断开连接期间被创建了,并且随后在客户端连接上之前又删除了,这种情况下,这个 watch
事件可能会被丢失。Watch
是轻量级的,其实就是本地 JVM 的 Callback
,服务器端只是存了是否有设置了 Watcher
的布尔类型由于资料内容太多,平台篇幅限制,小编就展现了以上部分面试专题与资料,如需获取以下全部面试资料,可以【点击这里】,可复制链接后用石墨文档 App 或小程序打开获取。
不要忘了一键三连哦!!!