介绍了zookeeper的基本原理和使用
简介
ZooKeeper是个分布式的服务协调框架。具体用途如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。它基于观察者的设计模式;zookeeper = 文件系统 + 监听通知机制。
特点:
- 最终一致性:Client不论连接到哪个Server,得到的数据都是一样的。
- 原子性:事务中的所有操作全部执行或者全部不执行。
- 顺序性:同一个client的请求顺序执行。
- 分区容错性:zookeeper是分布式的,所以在部分节点出现故障时,可以自己恢复。
数据结构
znode:zk是层级树状结构,一个节点就是znode。默认可存1M数据。
- 操作节点时可设置watcher。当节点状态发生变化时,就会触发watcher对应的操作,只触发一次。
- 永久节点:创建后永久存在,除非主动删除;临时节点:临时创建的,会话结束节点自动被删除
- 顺序节点:节点名称后面自动增加一个10位数字的序列号;非顺序节点:不加序列号
节点衍生出分类是为了迎合需求。临时节点可以记录服务器是否上线:当服务器下线,临时节点的数据消除。顺序节点可用于同一服务器多次上下线,每次名字都不同。很明显2个2分类,两两组合有4种节点。
下面是一个znode的数据结构:
# 一个znode的数据结构 |
补充:
zxid(ZooKeeper Transaction Id):ZooKeeper每次状态变化将会产生一个叫zxid的时间戳。
原理
基本流程:
客户端发请求(可带watcher) -> zk 选举与恢复 (没leader时) -> zk 读写数据 -> 返回数据(可触发watcher)
两端主要是监听器的原理,中间主要用到ZAB协议。
监听器原理
watcher 相当于一个的炸弹,客户端发请求时:如ls,get,set
等,可以给节点绑上炸弹。
如果触发了爆炸条件:ls
就是该节点有增加删减子节点;get set
就是该节点数据改变。
炸弹爆炸(只炸一次)也就是执行里面的回调函数。
很明显这里用户端至少需要启动两个线程:connect线程负责网络连接通信:绑炸弹并把任务发给zk与后续数据互传;listener线程监听炸弹爆炸信号。
ZAB协议
Zab协议(Zookeeper Atomic Broadcast),通过它来保证分布式事务的最终一致性。
这个内容很多,详细的可以参考:
主要功能:崩溃恢复(选举、数据恢复) 的 原子广播 (数据读写)
崩溃恢复
集群中必须有一个leader,leader出现故障时,采用投票选举新leader,它需要满足以下条件:
- 新选举出来的 Leader 不能包含未提交的 Proposal 。
- 新选举的 Leader 节点中含有最大的 zxid 。
- 得到超过一半选票者称为 Leader,因此zk集群个数为奇数
并不是所有节点都是 leader 和 follower ,还有observer,它不参与选举。作用是:可以增加集群数量,又减少投票选举时间。
选出leader后,进行数据恢复也就是同步,这个没啥,就是让它们其它节点数据都和leader同步,毕竟咱要确保最终一致性。恢复完毕后,就可以处理客户端的请求了。
读写数据
一般流程:
读请求,就是直接从当前节点中读取数据
写请求
- 客户端发起一个写操作请求。
- Leader 将客户端的请求转化为事务(Proposal),每个 Proposal 分配一个全局的ID,即zxid。
- Leader 为每个 Follower 分配一个单独的队列,然后将需要广播的 Proposal 依次放到队列中取,并且根据 FIFO 策略进行消息发送。
- Follower 接收到 Proposal 后,会首先将其以事务日志的方式写入本地磁盘中,写入成功后向 Leader 反馈一个 Ack 响应消息。
- Leader 接收到超过半数以上 Follower 的 Ack 响应消息后,即认为消息发送成功,可以发送 commit 消息。
- Leader 向所有 Follower 广播 commit 消息,同时自身也会完成事务提交。Follower 接收到 commit 消息后,会将上一条事务提交。
有意思的点
-
**如何保证消息有序:**在整个消息广播中,Leader会将每一个事务请求转换成对应的 proposal 来进行广播,并且在广播 事务Proposal 之前,Leader服务器会首先为这个事务Proposal分配一个全局单递增的唯一ID,称之为事务ID(即zxid),由于Zab协议需要保证每一个消息的严格的顺序关系,因此必须将每一个proposal按照其zxid的先后顺序进行排序和处理。
-
**用队列提高效率:**Leader 服务器与每一个 Follower 服务器之间都维护了一个单独的 FIFO 消息队列进行收发消息,使用队列消息可以做到异步解耦。 Leader 和 Follower 之间只需要往队列中发消息即可。如果使用完全同步的方式会引起阻塞,性能要下降很多。(我感觉这里应该不是FIFO 消息队列,应该是最小队列吧)
-
记住超过半数