一致性算法
问题
分布式系统中的一致性算法有哪些?Raft 算法的原理是什么?Paxos、ZAB、Gossip 各有什么特点?
答案
一致性算法分类
| 算法 | 类型 | 应用 |
|---|---|---|
| Paxos | 强一致性 | Google Chubby |
| Raft | 强一致性 | etcd、Consul、TiKV |
| ZAB | 强一致性 | ZooKeeper |
| Gossip | 最终一致性 | Redis Cluster、Cassandra |
Raft 算法
Raft 是目前最易理解的强一致性共识算法,保证在多数节点(> N/2)存活时系统正常运行。
三种角色:
| 角色 | 职责 |
|---|---|
| Leader | 处理所有客户端请求,管理日志复制 |
| Follower | 被动接收 Leader 的日志复制 |
| Candidate | 选举期间的临时角色 |
Leader 选举
选举流程:
- Follower 在 选举超时(150~300ms 随机)内未收到 Leader 心跳
- 转为 Candidate,任期号(Term)+1,投票给自己,并向其他节点请求投票
- 获得 多数票(> N/2) 后成为 Leader
- Leader 定期发送心跳维持地位
日志复制
日志条目只有被 多数节点 复制后才会被提交(committed)。
ZAB 协议(ZooKeeper)
ZAB(ZooKeeper Atomic Broadcast)是 ZooKeeper 的一致性协议,与 Raft 类似但有差异:
| 对比 | Raft | ZAB |
|---|---|---|
| Leader 选举 | 任期号 + 日志新旧 | epoch + 事务 ID(ZXID) |
| 日志连续性 | 严格连续 | 允许间隙(通过同步补齐) |
| 新 Leader | 可能有未提交日志 | 必须拥有最大 ZXID |
| 阶段 | Leader 选举 + 日志复制 | 发现 + 同步 + 广播 |
ZAB 的三个阶段:
- 发现(Discovery):选出拥有最大 ZXID 的节点作为 Leader
- 同步(Synchronization):Leader 将数据同步到所有 Follower
- 广播(Broadcast):正常处理写请求,类似 2PC(过半确认即提交)
Gossip 协议
Gossip 是一种去中心化的最终一致性协议,节点间像"谣言传播"一样扩散信息。
每个周期,每个节点随机选择几个节点交换信息,经过 轮后所有节点收到信息。
Redis Cluster 中的 Gossip:
- 每个节点每秒随机选 5 个节点,向其中最久没通信的发送 PING
- PING/PONG 消息携带集群拓扑信息(节点状态、slot 分配)
- 节点主观下线 → 超过半数报告 → 客观下线 → 故障转移
| 对比 | Raft/ZAB | Gossip |
|---|---|---|
| 一致性 | 强一致 | 最终一致 |
| 中心化 | 有 Leader | 去中心化 |
| 收敛速度 | 快 | 慢() |
| 网络开销 | 低 | 较高(大量冗余消息) |
| 容错性 | 需要多数存活 | 任意节点宕机不影响 |
常见面试问题
Q1: Raft 如何保证一致性?
答案:
Raft 通过以下机制保证一致性:
- Leader 唯一性:同一任期内最多一个 Leader(多数票选举)
- 日志匹配:如果两个节点的日志在同一 index 有相同 term,则该 index 之前的所有日志相同
- Leader 完整性:已提交的日志一定存在于后续任期的 Leader 中
- 多数提交:日志被多数节点复制后才提交
所以即使 Leader 宕机,新 Leader 一定包含所有已提交的日志。
Q2: Raft 的脑裂问题怎么解决?
答案:
网络分区可能导致两个子网各自选出 Leader(脑裂)。Raft 通过 多数派机制 自然解决:
- 5 个节点分成 [A,B,C] 和 [D,E] 两组
- [A,B,C] 有 3 个节点(多数),可以选出 Leader 并正常工作
- [D,E] 只有 2 个节点(少数),无法选出 Leader,拒绝写入
- 网络恢复后,[D,E] 的 Leader(旧 term)发现新 Leader 的更高 term,自动退为 Follower
Q3: ZooKeeper 的 ZAB 和 Raft 有什么区别?
答案:
核心思想相似(Leader 选举 + 日志复制 + 多数提交),主要区别:
- 选举条件:Raft 看 term + 日志长度,ZAB 看 epoch + ZXID
- 新 Leader 同步:Raft 新 Leader 可能有未提交的日志需要清理;ZAB 新 Leader 先做全量同步
- 读一致性:ZooKeeper 默认读可能返回旧数据(Follower 读),需要
sync()命令保证强一致读 - 设计目标:Raft 更通用,ZAB 专为 ZooKeeper 优化
Q4: 什么场景用 Gossip 而不是 Raft?
答案:
- Gossip:节点数很多(数百~数千)、不需要强一致性、去中心化。如 Redis Cluster(最多 1000 节点)、Cassandra
- Raft:节点数较少(3~7 个)、需要强一致性、有 Leader 协调。如 etcd、Consul、TiKV