本文ZooKeeper版本:3.8.0
ZooKeper实现数据一致性主要就是依赖其ZAB协议,ZAB协议就是借鉴了Paxos算法
ZAB协议包含两种,分别是原子广播和崩溃恢复
原子广播
原子:要么成功,要么失败,不存在中间状态(队列+2阶段提交)
广播:在分布式多节点中,不是所有节点都会接收到广播,但会过半通过。
- 客户端发送请求给Follower
- 所有的Follower在接收到请求之后,会转发给Leader(所有的事务请求都由Leader来处理)
- Leader将会将拿到的请求转化成事务提议,事务序列号Zxid+1。
- Leader将提议通过广播给所有的Follower,让其写入日志。(Leader会为每个Follower各设置一个队列,广播的时候把提议放入对应Follower的FIFO队列)
- 而Follower的操作结果将反馈给Leader。
- Leader在接收到Follower的反馈后,如果集群中有过半的Follower进行正确的ack反馈。Leader将会再次广播Follower ,发送commit消息,提交提议
崩溃恢复
所谓的崩溃恢复 就是在Leader节点崩溃下线后,从有效的Follower节点中推选出一个新的Leader,从而让整个集群继续对外提供服务,在选择的阶段可能会导致各个节点存在数据不一致的问题。
进入崩溃恢复模式的情况
- 服务首次启动
- 当Leader服务器出现网络/重启等问题导致其无法和过半的服务器正常连接。
恢复模式的策略:
- 最先选择zxid最大的节点作为Leader
- 新的Leader 会把事务日志中未提交的请求处理掉
Leader选举原理(ZAB有主)
崩溃恢复其实就是选主,有两种情况下的选主,一个是集群首次启动,另一个是运行中Leader崩溃
在选举的时候会参考两个重要的参数:
- 事务ID(zxid): 值越大说明权重越大,其数据最新
- 服务器ID(myid): 自定义的服务节点ID,值越大权重越大
过半通过的数据 产生的zxid才是真实有效的
集群首次启动选主
特点:每个节点的数据都是一致的,尤其zxid,不同的是myid
假设此集群共有3个节点,首次启动所以每个节点的zxid都是0,而myid则是不同的1,2,3,所以三个节点的信息分别是node1(1,0),node2(2,0),node3(3,0)。
然后依次启动三个节点,当第二台机器node2启动的时候,node1和node2就可以互相通信的。
- node1节点启动 投票(1,0),给自己投1票 ,共三台机器此时未过半,所以没有选出leader,node1的状态是Looking。
投票结果:node1: 1票 - node2节点启动,发起投票(2,0),同时给已经启动的node1节点发送信息(每个节点发起投票的同时也会引发其他的节点再次投票)。
投票结果: node1: 1票,node2: 1票 - node1接收到node2的投票信息,对比zxid和myid,发现node2的myid更大,此时node1就会改选重新投node2
投票结果:node1:0票,node2: 2票
对比规则:
- 比较epoch,来确认是同一轮的投票
- 再比较zxid,较大的会作为Leader
- zxid相同再比较myid,较大的作为Leader
- 综合现有机器的投票结果,node1是0票,node2是2票(过半)。此时node1的状态是Follower,node2的状态是Leader。
- 继续启动node3节点,已经存在Leader,node3会直接加入变更为Follower。
测试:
三台机器的myid分别是1,2,3
如下是三台的端口设置,第一个端口是leader端口,第二端口是leader选举的时候各节点通信的端口
先启动node1
没有其他节点和其通信,所以会出现错误,暂时没有节点状态。
启动node2
随着node2的启动,node1节点也不会出现错误日志,接着变成following状态,而node2变成leading状态
接着查看节点状态: node1=follower node2=leader
启动node3
node3在启动之后 会是following状态,在完成数据同步之后又会变成follower状态
运行中Leader崩溃 选主
特点:每个节点的数据不一定一致的,myid不同,zxid也可能不同
还是上面的3个节点的集群,运行一段时间之后 每个节点的zxid都有了变化分别是4,4,3,myid还是原来的,分别是1,2,3,所以三个节点的信息分别是node1(1,4),node2(2,4),node3(3,3)。node2是Leader节点
这时候如果node2节点因为故障断开连接, 剩下两个节点中任意一个检测到Leader不存了(心跳监控),都会向集群中的其他节点发起投票(投自己,每个节点发起投票的同时也会引发其他的节点再次投票),每个节点在收到其他节点投票信息后比较自己手里的信息 然后选择一个节点进行投票或回复(参考上面的投票方式),最终确定一个Leader。
我是纪先生,用输出倒逼输入而持续学习,持续分享技术系列文章,以及全网值得收藏好文,欢迎关注公众号,做一个持续成长的技术人。