文章目录
- 1、什么是Zookeeper?
- 2、ZooKeeper的基本数据结构是什么?
- 3、Zookeeper的节点类型有哪些?
- 4、Zookeeper的特点
- 5、ZooKeeper如何保证数据一致性?
- 6、什么是ZAB协议?
- 7、Zookeeper的ACL机制是什么?
- 8、Zookeeper的选举算法是什么?
- 9、Zookeeper 常用命令
- 10、ZooKeeper JavaAPI 操作
- 11、Zookeeper的Watcher机制是什么?
- 12、ZooKeeper分布式锁原理
- 13、ZooKeeper集群
- 14、ZooKeeper集群存在脑裂问题吗
- 15、zk的初始化选举和崩溃选举过程
- 16、zk的数据同步原理
- 17、Zookeeper 的典型应用场景
- 18、请谈谈ZooKeeper对事务性的支持
- 19、简述zk中的观察者机制
1、什么是Zookeeper?
Zookeeper 翻译过来就是动物园管理员,他是用来管 Hadoop (大象) 、Hive(蜜蜂)、Pig(小猪)的管理员,简称zk。
Zookeeper是 Apache Hadoop项目下的一个子项目,是一个开源的分布式协调服务
。
提供的主要功能包括:
配置管理
、命名服务
、分布式同步
、分布式锁
、集群管理
。
2、ZooKeeper的基本数据结构是什么?
ZooKeeper使用树形
数据结构,类似于文件系统的目录结构
,拥有一个层次化结构,节点称为Znode
。
每个Znode节点上都会保存自己的数据
和节点信息
,并且有一个唯一的路径
。
Zookeeper为了保证高吞吐和低延迟,在内存中维护了这个树状的目录结构,这种特性使得Zookeeper不能用于存放大量的数据,
每个节点的存放数据上限为1M
。
节点内容
:二进制数组 (bvte data[])
用来存储节点的数据、ACL访问控制、子节点数据 (因为临时节点不允许有子节点,所以其子节点字段为null),记录自身状态信息的stat。
stat +节点路径可以查看状态信息
czxid:创建节点的事务id
mzxid:最后一次被更新的事务id
pzxid:子节点最后一次被修改的事务id
ctime: 创建时间
mtime:最后更新时间
version: 版本号、表示的是对节点数据内容,子节点信息或ACL信息的修改次数可以避免并发更新问题,使用之前获取的版本进行CAS操作更新
cversion:子节点版本号
aversion: acl的版本号
ephemeralOwner: 创建节点的sessionld,如果是持久节点、值为0dataLenght: 数据内容长度
3、Zookeeper的节点类型有哪些?
- 持久节点(Persistent znode):创建后一直存在,直到显式删除。
- 临时节点(Ephemeral znode):客户端会话存在期间存在,客户端会话结束后临时节点被删除。
- 持久顺序节点(Persistent Sequential znode):顺序节点是在创建时自动分配一个顺序号,用于唯一标识。
- 临时顺序节点(Ephemeral Sequential znode)
持久节点适用于存储配置信息等长期数据,临时节点适用于存储临时状态等短期数据。
4、Zookeeper的特点
- 最终一致性:客户端看到的数据最终是一致的。
- 可靠性:服务器保存了消息,那么它就一直都存在。
- 实时性:ZooKeeper 不能保证两个客户端同时得到刚更新的数据。
- 独立性(等待无关):不同客户端直接互不影响。
- 原子性:更新要不成功要不失败,没有第三个状态。
5、ZooKeeper如何保证数据一致性?
通过分布式一致性算法ZAB (ZooKeeper Atomic Broadcast)。
6、什么是ZAB协议?
ZAB协议是一种原子广播协议
,保证所有ZooKeeper服务器上的数据一致性。包含崩溃恢复
和消息广播
两部分。
ZAB协议的工作流程:
- 领导者选举:
系统初始化时或现有领导者失效时,所有节点通过选举过程选出新的领导者。选举过程依赖于Zookeeper的选举算法,如Fast Paxos变种。 - 数据同步:
新的领导者选出后,必须与跟随者同步数据。领导者会发送最新的事务日志给跟随者,确保所有节点的状态一致。 - 事务广播:
领导者接收到客户端的写请求后,将请求转换成事务,并将事务广播给所有跟随者。跟随者接收到事务后记录日志,并向领导者发送确认。 - 提交(Commit):
一旦领导者接收到多数(过半数)跟随者的确认,便会提交该事务并将其应用到自己的状态机。随后,领导者会将提交通知发送给所有跟随者,指示它们也应用该事务。 - 故障恢复:
如果领导者失效,ZAB协议会通过重新选举新领导者来恢复系统的正常运行。新的领导者通过数据同步和事务广播机制确保系统继续保持一致性。
zk保证最终一致性
如果写请求落在了follow节点,也会转交给leader处理
7、Zookeeper的ACL机制是什么?
ACL(Access Control List)用于控制对znode的访问权限,分为创建、删除、读取、写入和管理权限。
ACL包括两个部分:scheme和id。scheme表示认证方案,如world、auth、digest等。id表示认证方案对应的标识符,如anyone、username、password等。Zookeeper提供了一些API来设置和获取ACL。
8、Zookeeper的选举算法是什么?
Zookeeper使用的选举算法是基于Paxos协议的Zab(Zookeeper Atomic Broadcast)协议。在一个Zookeeper集群中,有一个Leader节点和多个Follower节点。Leader节点负责处理客户端的读写请求,Follower节点负责与Leader节点保持数据一致性。如果Leader节点故障,则集群会自动选举一个新的Leader节点。
9、Zookeeper 常用命令
1)Zookeeper 服务端常用命令
启动 ZooKeeper 服务: ./zkServer.sh start
查看 ZooKeeper服务状态: ./zkServer.sh status
停止 ZooKeeper 服务: ./zkServer.sh stop
重启 ZooKeeper 服务: ./zkServer.sh restart
2)Zookeeper 客户端常用命令
链接服务端:
# 连接ZooKeeper服务端
/zkCli.sh -server ip:port
# 查看指定节点下的子节点目录
ls / #[zookeeper]
# 继续查看下一级节点
ls /zookeeper
# 创建节点app1 ,内容存test
create /app1 test
# 获取节点app1内容
get /app1
# 修改节点app1 ,内容存test2
set /app1 test2
# 删除节点
delete /app1
# 创建节点app1的子节点
create /app1/apppp1
create /app1/apppp2
# 删除apppp1
delete /app1/apppp1
# 删除带有子节点的节点
deleteall /app1
创建不同类型节点命令
# 创建临时节点
create -e /app1
# 创建顺序节点
create -s /app1
# 创建临时顺序节点
create -es /app1
# 查询节点详细信息
ls -s /节点path
10、ZooKeeper JavaAPI 操作
常见的ZooKeeper Java APl:
- 原生Java API不好用
- ZkClient
- Curator
Curator项目的目标是简化ZooKeeper 客户端的使用.
Curator 最初是 Netfix研发的,后来捐献了 Apache基金会目前是Apache 的顶级项目。
注:Curator是 Apache ZooKeeper 的Java客户端库,所以使用时也要注意和zk的版本问题。
11、Zookeeper的Watcher机制是什么?
Zookeeper的Watcher机制是一种事件通知机制
,用于监听Znode的变化。
当Znode发生变化时,Zookeeper会通知客户端,客户端可以注册Watcher来监听这些事件。Watcher是一次性的
,即一旦触发一次事件,Watcher就失效了,需要重新注册。
Curator入了 Cache 来实现对 ZooKeeper 服务端事件的监听。ZooKeeper提供了三种Watcher:
- NodeCache: 只是监听某一个特定的节点
- PathChildrenCache:监控一个ZNode的子节点
- TreeCache:可以监控整个树上的所有节点,类似于PathChildrenCache和NodeCache的组合
new ZooKeeper(String connectString, int sessionTimeout,Watcher watcher)
#这个watcher将作为整个ZooKeeper会话期间的上下文,一直被保存在客户端ZKWatchManager的defaultWatcher
也可以动态添加watcher: getData0,exists,getChildren会覆盖上边默认的watcher。
Zookeeper 允许客户端向服务端的某个 znode 注册一个 Watcher 监听,当服务端的一些指定事件,触发了这个 Watcher ,服务端会向指定客户端发送一个事件通知来实现分布式的通知功能,然后客户端根据 Watcher 通知状态和事件类型做出业务上的改变。大致分为三个步骤:
客户端注册 Watcher
1、调用 getData、getChildren、exist 三个 API ,传入Watcher 对象。
2、标记请求request ,封装 Watcher 到 WatchRegistration 。
3、封装成 Packet 对象,发服务端发送request 。
4、收到服务端响应后,将 Watcher 注册到 ZKWatcherManager 中进行管理。
5、请求返回,完成注册。
服务端处理 Watcher
1、服务端接收 Watcher 并存储。
2、Watcher 触发
3、调用 process 方法来触发 Watcher 。
客户端回调 Watcher
1,客户端 SendThread 线程接收事件通知,交由 EventThread 线程回调Watcher 。
2,客户端的 Watcher 机制同样是一次性的,一旦被触发后,该 Watcher 就失效了。
client 端会对某个 znode 建立一个 watcher 事件,当该 znode 发生变化时,这些 client 会收到 zk 的通知,然后 client 可以根据 znode 变化来做出业务上的改变等。
12、ZooKeeper分布式锁原理
ZooKeeper分布式锁原理:
核心思想:当客户端要获取锁,则创建节点,使用完锁,则删除该节点。
1.客户端获取锁时,在该节点下创建临时
顺序
节点,比如test。
2.然后获取test节点下面的所有子节点,客户端获取到所有的子节点之后,如果发现自己创建的子节点序号最小,那么就认为该客户端获取到了锁。使用完锁后,将该节点删除。
3.如果发现自己创建的节点并非test节点所有子节点中最小的,说明自己还没有获取到锁,此时客户端需要找到比自己小的那个节点,同时对其注册事件监听器,监听删除事件
。
4.如果发现比自己小的那个节点被删除,则客户端的Watcher会收到相应通知,此时再次判断自己创建的节点是否是lock子节点中序号最小的,如果是则获取到了锁如果不是则重复以上步骤继续获取到比自己小的一个节点并注册监听。
如果持久化节点,宕机了锁就没办法删除,因为要找最小的,所以是顺序节点,而且用临时顺序节点,如果某个客户端创建临时顺序节点之后,自己宕机了,除对应的临时顺序节点,相当于自动释放锁,或者是自动取消自己的排队。解决了惊群效应
13、ZooKeeper集群
在一个集群中,最少需要 3 台。或者保证 2N + 1 台,即奇数。为什么保证奇数?主要是为了选举算法。
集群搭建至少需要三套的zoo.cfg和三个myid文件
其中一个节点zoo.cfg配置内容:
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/tmp/zookeeper/data1
admin.serverPort=8081
clientPort=2181
server.1=192.168.65.66:1888:1887
server.2=192.168.65.66:2888:2887
server.3=192.168.65.66:3888:3887
启动一个节点是不可用的,启动2个以上才可用
在目录/tmp/zookeeper/data1下需要创建一个myid
文件,文件内容为1
对应上边文件中的server.1中的1
选举PK:优先比zxid大小(zxid大的数据更新),一样再比myid
14、ZooKeeper集群存在脑裂问题吗
ZooKeeper脑裂
是指一个集群环境中出现了多个Master节点
,导致数据不一致和数据问题。这种情况通常发生在网络故障导致集群中部分节点失去与Master节点的连接。而在这些节点看来,Master节点已经失效,因此它们会选举新的Master节点。在这个过程中,可能会出现多个Master节点,导致脑裂问题。
假设6个节点,部署两个机房:
第一种3-3分,如果一个机房挂掉,和leader保持心跳的节点不到半数以上了,也就是没有4个了,那就不会工作了,也就没有脑裂问题
另一种:4-2分,如果一个机房挂掉,leader节点通讯的节点仍然有4个,那么不影响任何,继续工作,也不会产生脑裂。
所以ZooKeeper选举过半机制决定了不会产生脑裂问题
。
15、zk的初始化选举和崩溃选举过程
关键信息:zxld:事务id,sld:节点id
先对比zxld,再对比sld,先投自己,选票内容 (zxld,sld),遇强改投
投票箱:每个节点在本地维护自己和其他节点的投票信息,改投时需要更新信息,并广播
节点状态:
- LOOKING,竞选状态。
- FOLLOWING,随从状态,同步leader状态,参与投票
- OBSERVING,观察状态,同步leader状态,不参与投票
- LEADING,领导者状态
初始化选举:没有历史数据,5个节点为例
- 节点1启动,此时只有一台服务器启动,它发出去的请求没有任何响应,所以它的选举状态一直是LOOKING状态
- 节点2启动,它与节点1进行通信,互相交换自己的选举结果,由于两者都没有历史数据,所以serverld值较大的服务器2胜出,但是由于没有达到半数以上,所以服务器1,2还是继续保持LOOKING状态
- 节点3启动,与1、2节点通信交互数据,服务器3成为服务器1.2.3中的leader,此时有三台服务器选举了3,所以3成为leader
- 节点4启动,理论上服务器4应该是服务器1,2,3,4中最大的,但是由于前面已经有半数以上的服务器选举了服务器3,所以它只能切换为follower
崩溃选举:
- leader故障后,follower进入looking状态变更状态
- 各节点投票,先投自己 (zxld,sld),再广播投票
- 接收到投票,对比zxld和sld,如果本节点小、则将票改为接收的投票信息,并记录投票信息,重新广播。否则本节点大、则可不做处理
- 统计本地投票信息,超过半数,则切换为leading状态并广播
16、zk的数据同步原理
根据这三个参数的大小对比结果,选择对应的数据同步方式。
- peerLastZxid:(Follower或observer) 最后处理的zxid.【也就是从节点目前最新数据是什么】
- minCommittedLog: Leader服务器proposal缓存队列committedLog中的最小的zxid
- maxCommittedLog: Leader服务器proposal缓存队列committedLog中的最大的zxid
Zookeeper中数据同步一共有四类,如下
- DIFF: 直接差异化同步
peerlastZxid介于minCommittedLog和maxCommittedLog之间 - TRUNC+DIFF: 先回滚再差异化
当Leader服务器发现某个Learner包含了一条自己没有的事务记录那么就需要让该Learner进行事务回滚到Leader服务器上存在的 - TRUNC: 仅回滚同步
peerlastZxid大于maxCommittedLog,Leader会要求Learner回滚到ZXID值为maxCommitedLog对应的事务操作 - SNAP:全量同步
- peerLastZxid 小于minCommittedLog
17、Zookeeper 的典型应用场景
通过对 Zookeeper 中丰富的数据节点进行交叉使用,配合 Watcher 事件通知机制,可以非常方便的构建一系列分布式应用中会涉及的核心功能,如:
(1)数据发布/订阅: 配置中心
(2)负载均衡: 提供服务者列表
(3)命名服务: 提供服务名到服务地址的映射
(4)分布式协调/通知: watch机制和临时节点,获取各节点的任务进度,通过修改节点发出通知
(5) 集群管理: 是否有机器退出和加入、选举 master
(6)分布式锁
(7) 分布式队列
18、请谈谈ZooKeeper对事务性的支持
ZooKeeper对于事务性的支持主要依赖于四个函数,zoo_create_op init、zoo _delete_op init、zoo set op init以及zoo check op init。
每一个函数都会在客户端初始化一个operation,客户端程序有义务保留这些operations.当准备好一个事务中的所有操作后,可以使用zoo_multi
来提交所有的操作,由zookeeper服务来保证这一系列操作的原子性。也就是说只要其中有一个操作失败了,相当于此次提交的任何一个操作都没有对服务端的数据造成影响。Zoo multi的返回值是第一个失败操作的状态信号
19、简述zk中的观察者机制
peerType=observer
server.1:locahost:2181:3181:observer
观察者的设计是希望能动态扩展zookeeper集群又不会降低写性能。
如果扩展节点是follower,则写入操作提交时需要同步的节点数会变多,导致写入性能下降,而follower又是参与投票的、也会导致投票成本增加
observer
是一种新的节点类型,解决扩展问题的同时,不参与投票
、只获取投票结果,同时也可以处理读写请求,写请求转发给leader。负责接收leader同步过来的提交数据,observer的节点故障也不会影响集群的可用性
。
跨数据中心部署。把节点分散到多个数据中心可能因为网络的延迟会极大拖慢系统。使用observer的话,更新操作都在一个单独的数据中心来外理,并发送到其他数据中心,让其他数据中心的节点消费数据.
无法完全消除数据中心之间的网络延迟,因为observer需要把更新请求转发到另一个数据中心的leader,并处理同步消息,网络速度极慢的话也会有影响,它的优势是为本地读请求提供快速响应
。