4. 分布式一致性协议:Paxos、Raft、Zab协议的原理与对比,Leader选举机制
说到分布式系统,一致性协议是绕不开的硬骨头。我刚开始接触这块时,也被Paxos搞得晕头转向。后来在项目中摸爬滚打,才慢慢理清了脉络。今天咱们就聊聊这三个主流协议:Paxos、Raft和Zab。
4.1 为什么需要一致性协议?
说白了,分布式系统里最怕的就是「脑裂」。多个节点各说各话,数据乱成一锅粥。你想想看,一个集群里三个节点,A说值是1,B说值是2,C说值是3——到底听谁的?
一致性协议就是来解决这个问题的。它保证所有节点最终达成一致,不会出现数据打架的情况。我在做电商订单系统时,就遇到过因为一致性没做好,导致同一个订单被重复发货的惨案...嗯,从那以后我对这块格外上心。
4.2 Paxos:祖师爷级别的协议
Paxos是Lamport大神在1990年提出的。说实话,它很强大,但也很难懂。我读原论文时,Lamport用了一个古希腊议会的故事来比喻,看得我云里雾里。
4.2.1 Paxos的核心角色
- Proposer(提议者):负责提出提案
- Acceptor(接受者):负责投票表决
- Learner(学习者):负责学习最终结果
4.2.2 Paxos的两阶段提交
Paxos的核心是两阶段提交:Prepare阶段和Accept阶段。
// 伪代码示例:Paxos Prepare阶段
Proposer发送Prepare(n)给所有Acceptor
Acceptor响应:
- 如果n大于之前见过的任何编号,承诺不再接受小于n的提案
- 返回已接受的最大编号提案(如果有)
// 伪代码示例:Paxos Accept阶段
Proposer收到多数派响应后,发送Accept(n, value)给所有Acceptor
Acceptor响应:
- 如果没有收到更大的Prepare请求,则接受该提案
我个人习惯把Paxos理解成「先占坑,再填坑」。Prepare阶段就是占坑,告诉别人「这个编号我要了」;Accept阶段才是真正填内容。
关键点:Paxos保证安全性(Safety),但不保证活性(Liveness)。也就是说,它不会产生错误结果,但可能永远达不成一致——这就是著名的「活锁」问题。
4.3 Raft:更易理解的一致性协议
Raft是2013年提出的,目的就是让一致性协议变得好懂。我在项目中首选Raft,因为它真的「人话」多了。
4.3.1 Raft的三个状态
| 状态 | 说明 | 超时时间 |
|---|---|---|
| Follower(跟随者) | 被动响应请求 | 随机150-300ms |
| Candidate(候选者) | 发起选举 | 选举超时 |
| Leader(领导者) | 处理所有客户端请求 | 心跳间隔 |
4.3.2 Leader选举机制
Raft的Leader选举是我见过最优雅的设计。它把问题拆成了几个小步骤:
- 触发选举:Follower收不到Leader心跳,超时后变成Candidate
- 发起投票:Candidate给自己投票,并请求其他节点投票
- 赢得选举:获得多数派(超过半数)投票的成为新Leader
- 任期机制:每个任期(Term)只有一个Leader
避坑指南:我曾经在部署Raft集群时,把节点数设成了偶数(4个)。结果网络分区时,两边各2个节点,谁也拿不到多数派,整个集群就挂了。记住:Raft集群节点数最好是奇数,3或5最常用。
4.4 Zab:ZooKeeper的原子广播协议
Zab是ZooKeeper使用的协议。它和Raft很像,但有一些关键区别。我在做配置中心时,底层就是Zab协议。
4.4.1 Zab的核心流程
- 发现阶段:新Leader收集所有Follower的最新数据
- 同步阶段:Leader把数据同步给所有Follower
- 广播阶段:正常处理客户端请求,进行原子广播
4.4.2 Zab的Leader选举
Zab的选举机制和Raft不太一样。它使用「投票轮次+数据新鲜度」来决定谁当Leader。数据越新的节点,越有可能当选。
// Zab选举的投票比较规则
if (vote.epoch > current.epoch) {
选择epoch更大的
} else if (vote.epoch == current.epoch) {
if (vote.zxid > current.zxid) {
选择zxid更大的(数据更新)
} else {
选择myid更大的(节点ID)
}
}
注意:Zab的选举过程中,如果出现平局(两个节点数据一样新),会按照节点ID排序。所以节点ID越小,在平局时越有优势。我建议给核心节点分配较小的ID。
4.5 三大协议对比
| 特性 | Paxos | Raft | Zab |
|---|---|---|---|
| 易理解性 | 难 | 易 | 中 |
| Leader选举 | 无固定Leader | 强Leader | 强Leader |
| 数据顺序 | 不保证全局有序 | 保证全局有序 | 保证全局有序 |
| 典型应用 | Chubby | Etcd、Consul | ZooKeeper |
| 工程实现难度 | 高 | 低 | 中 |
4.6 我的选择建议
在实际项目中,我一般这样选:
- 新项目:首选Raft。文档多、实现简单、社区活跃。Etcd和Consul都是好例子。
- 需要强一致性且已有ZooKeeper:用Zab。别折腾,ZooKeeper很成熟。
- 学术研究或特殊场景:才考虑Paxos。说实话,我工作这么多年,没自己实现过Paxos——太容易出bug了。
核心总结:一致性协议的本质就是「多数派决策」。不管是Paxos、Raft还是Zab,核心思想都一样:让多数节点说了算。区别在于实现细节和易用性。我个人觉得,选协议就像选工具——顺手最重要。
好了,这一章就聊到这儿。下一章咱们会深入Raft的日志复制和安全性,到时候我会分享一个我在生产环境遇到的Raft脑裂案例,保证让你印象深刻。