Zookeeper的ZAB协议
前言
Zookeeper 是一个开源的分布式协调服务,提供了分布式数据一致性的解决方案。分布式应用可以基于它实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、分布式锁和分布式队列等功能。
ZAB的全称是Zookeeper Automatic Broadcast,即 Zookeeper 原子广播协议,一种专门为Zookeeper设计的支持崩溃恢复的原子广播协议。
基本概念
集群角色
通常在分布式系统中,构成一个集群的每一台机器都有自己的角色,最典型的集群模式就是 Master/Slave 模式。但是在 Zookeeper 集群没有 Master 和 Slave 的概念,取而代之的是如下角色:
- Leader
- 在同一个Zookeeper集群中只能有一个 Leader。
- Leader 可以提供读写功能对 Client,其他 Follower 只提供读取功能。
- Follower
- 同一个集群中可以有多个 Follower,Follower(Leader也算作Follower)的数量最好是奇数。
- Follower 提供读取数据功能对 Client,如果Follower 接收到写请求,那么它会转发这个请求到 Leader。
- Follower 可以参与集群的 Leader 选举。
- Observer
- 同一个集群中可以有多个 Observer,且 Observer 只负责读取功能,不参与 Leader 选举过程。
ZooKeeper 在读取高于写入的应用中具有特别高的性能,因为写入操作涉及到同步所有服务器的状态。所以一般而言,Zookeeper集群中,Observer的数量应该最大,Follower和Leader的数量不用太多,但是数量最少也要达到3个节点。
ZXID介绍
Zxid 是一个long型(64位)整数,分为两部分:epoch(纪元,前32位)和counter(计数器,后32位),是一个全局有序的数字。
- epoch
- epoch值随着新leader的产生而变化,每当新选举一个leader,epoch值会自增1。
- 如果counter已经达到最大值,即后32位全为1,则进位,此时epoch会自增1。
- counter
- 每次committed一个proposal,counter值都会自增1。
Zxid分类:
- cZxid
- 创建当前节点时的事务ID。
- mZxid
- 最近修改当前节点时的事务ID。
- pZxid
- 表示当前节点的子节点列表最后一次修改的事务ID。
ZAB协议介绍
ZAB 协议是专门为 Zookeeper 设计的支持崩溃可恢复的原子广播协议,所以这是一个有特定使用场景的协议,并不具备通用性。
ZAB 协议包括两种基本的模式:崩溃恢复和消息广播。
崩溃恢复和消息广播模式会一直保持来回切换。当集群在启动过程中、Leader 服务器崩溃、集群出现网络中断或者重启等异常信息时,集群会切换到崩溃恢复模式,选出新的 Leader 服务器。当 Leader 服务器激活成功后,集群会退出崩溃恢复模式,然后切换到消息广播模式。
崩溃恢复(选举)
关于Zookeeper的选举有三个问题需要解答:选举时机、选举规则和选举流程
选举时机
Zookeeper 的选举时机分成以下几种情况:
- 集群启动过程中
- Zookeeper 集群要求最少有3个可以参与选举的节点(作为observer的节点不能参与选举)。
- 集群启动过程中,如果集群中没有Leader,那么集群就会进入选举状态。
- 集群运行过程中
- 如果 Leader 节点崩溃,集群失去了 Leader 会进入崩溃恢复状态,开始选举。
- 如果集群发生网络故障,比如Leader 服务器失去了与过半 Follower的联系,集群就会进入崩溃恢复模式,开始选举。
选举规则(选举算法)
-
在启动过程中选举leader的情况比较简单,因为此时整个集群的所有节点都没有数据,所以选举leader依据myid的值,即myid最大的节点当选leader。myid值只要不是-1,其他任何值都可以。
-
如果集群已经开始运行,然后进入崩溃恢复模式,此时选举需要根据以下条件决定(优先级从高到低):
- epoch
- counter
- myid
如果一个参与选举的服务器的数据的zxid最大,那么这个服务器就作为新 Leader。如果所有参与选举的服务器的zxid都一致,那么myid值最大的服务器当选新 Leader。
数据同步功能:
在成为新 Leader 之后,在正式开始工作之前,新 Leader 还需要做一个同步数据的工作,保证集群中服务器的数据一致。首先,Leader 服务器会为每一个 Follower 服务器准备一个队列,然后将那些没有被各个 Follower 服务器同步的事务以 proposal 消息的形式逐个发送到各个队列中,并在每一个 proposal 消息后再发送一个 committed 消息,以表示该 proposal 已经被提交。等到 Follower 将所有未同步的 proposal 写入本地文件中后,返回 ACK 消息给 Leader 服务器,该 Follower 服务器会被加入到 Leader 服务器可用的 Follower 列表。
同步数据过程中,为了确保正确地同步数据,ZAB 做了如下规定:
- ZAB 协议需要确保那些已经在 Leader 服务器上提交的事务proposal最终被所有服务器提交。
- 如果proposal 已经被提交,说明该proposal 已经被之前的 quorum 确认,这是一个有效的proposal,所以新 Leader 需要将已经被提交的 committed 的 proposal 同步给所有 Follower。
- ZAB 协议需要确保丢弃那些只在 Leader 服务器上被提交的事务。
- 如果 proposal 没有被提交,那么说明该proposal还没有被之前的 quorum 确认,不是一个正式的proposal,所以新 Leader 不需要同步到其他 Follower,直接丢弃即可。
选举流程
- 通过画图解决
消息广播
ZAB 协议的消息广播过程使用了原子广播协议,类似一个二阶段提交过程。
- 第一阶段
- 针对客户端的请求,Leader 节点为请求生成一个proposal,然后将proposal发送到所有Follower的队列中。
- 然后收集从Follower返回的 ACK 确认信息。
- 如果返回的ACK确认信息票数超过了 N/2 +1,那么就进入第二阶段。
- 如果返回的ACK确认信息票数没有超过 N/2 +1 ,那么这个proposal就被丢弃。
- 第二阶段
- 如果针对某一个 proposal,Leader 已经收到了足够的 ACK 票数,那么 Leader 会发送 committed 信息给所有的 Follower,仍旧发送到各个 Follower 的队列中。
- Follower 收到 committed 消息后将对应的proposal入库,即写入本地的日志文件中。
和二阶段提交不同,ZAB 协议的二阶段提交不需要等待所有的Follower返回 ACK 消息后才进行第二阶段的committed操作,只需要超过 N/2 +1 的节点返回 ACK 信息即可。
在整个消息广播过程中,如果发生了 Leader 崩溃或者Leader和Followers之间的网络不通,那么整个集群就会进入崩溃恢复模式,防止发生整个集群数据不一致的问题。进入崩溃恢复模式后,集群会重新选择 Leader,然后同步数据。
如果之前的Leader 又重新连入的网络,那么该节点也只能作为Follower加入集群,即使该节点有值更大的 zxid,那么这些proposal也只能被丢弃。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构