面试知识库
困难

Raft协议#

一句话答案#

Raft 将分布式共识分解为 Leader 选举、日志复制、安全性三个子问题,通过”多数派同意即提交 + term 递增防脑裂”保证一致性,比 Paxos 更易理解和实现。

核心要点

Raft 三大子问题#

1. Leader Election —— 谁来当老大?
2. Log Replication —— 老大怎么让大家保持一致?
3. Safety —— 怎么保证已提交的数据不丢?
plaintext

1. Leader 选举#

节点三种角色:

  • Leader:处理所有写请求,向 Follower 复制日志
  • Follower:接受 Leader 的日志复制,响应读请求(部分实现)
  • Candidate:正在竞选 Leader 的节点

选举流程:

1. Follower 在 election timeout(随机 150ms~300ms)内没收到 Leader 心跳
2. 转为 Candidate,term+1,投自己一票
3. 向所有节点发送 RequestVote RPC
4. 收到多数票 → 成为 Leader,立即发送心跳宣告
   ├── 同一 term 内每个节点只投一票(先到先得)
   └── 投票条件:Candidate 的日志至少和自己一样新(term 更大,或 term 相同但 logIndex 更大)
5. 如果没拿到多数票 → 等待随机超时后重新发起
plaintext

为什么用随机超时? 避免多个节点同时发起选举导致反复平票(split vote)。

2. 日志复制#

流程:

1. 客户端发送写请求到 Leader
2. Leader 将命令追加到自己的日志(uncommitted)
3. Leader 并行发送 AppendEntries RPC 给所有 Follower
4. Follower 验证日志一致性(prevLogIndex + prevLogTerm 匹配)
   ├── 匹配 → 追加日志,返回 success
   └── 不匹配 → 返回 fail,Leader 递减 nextIndex 重试
5. Leader 收到多数 Follower 的 success → 提交日志(committed)
6. Leader 返回客户端成功
7. 下一次心跳/AppendEntries 通知 Follower 提交已 committed 的日志
plaintext

日志匹配属性(Log Matching Property):

  • 如果两个节点的日志在相同 index 有相同 term → 该 index 及之前的所有日志完全相同
  • 这保证了 Leader 可以通过逐步回退 nextIndex 来对齐 Follower 的日志

3. 安全性保证#

三个关键保证:

保证含义
Election Safety同一 term 内最多一个 Leader
Leader Completeness已提交的日志一定存在于后续所有 Leader 中
State Machine Safety所有节点按相同顺序执行相同的已提交日志

Leader Completeness 怎么保证?

  • 投票时检查 Candidate 日志是否”足够新”
  • Candidate 的最后一条日志 term 更大,或 term 相同 index 更大
  • → 拥有最新已提交日志的节点才可能当选

脑裂防护#

场景:网络分区导致 Leader A 和 Follower B/C 分到不同网络

分区 1: [A(Leader, term=3)]
分区 2: [B, C] → B 超时发起选举,term=4,C 投票 → B 成为新 Leader

此时两个 "Leader":A(term=3) 和 B(term=4)

A 无法获得多数确认(只有自己)→ 任何写入都不会被提交
B 有多数节点 → 正常工作

网络恢复后:
A 收到 term=4 的消息 → 发现自己 term 过期 → 自动降级为 Follower
A 的未提交日志被 B 的日志覆盖

关键:term 递增 + 多数派 = 自动解决脑裂,不会出现两个有效 Leader
plaintext

日志压缩(Snapshot)#

  • 日志无限增长 → 内存和恢复时间不可控
  • 定期做快照:将状态机当前状态保存为 Snapshot
  • Snapshot 之前的日志可以丢弃
  • 新节点加入时先传 Snapshot,再增量同步

ZAB(ZooKeeper)vs Raft 对比#

维度ZABRaft
设计目标ZooKeeper 专用的原子广播通用分布式共识
Leader 选举选最大 ZXID 的节点随机超时 + 多数投票
任期标识epochterm
模式恢复模式 / 广播模式无显式模式,选举和复制无缝衔接
日志对齐恢复阶段有 DIFF/TRUNC/SNAPAppendEntries 逐步回退对齐
工程实现etcd 不用、ZooKeeper 用etcd / Consul / TiKV 都用 Raft

本质相同: 都是 Leader-based、多数派确认、心跳检测。Raft 更强调可理解性。

Raft vs Paxos#

维度PaxosRaft
可理解性极难(论文公认晦涩)易理解(论文以可理解性为目标)
LeaderMulti-Paxos 需要 Leader,Basic Paxos 不需要强制 Leader
工程实现很少有完全按论文实现的大量工程实现(etcd, Consul)
面试回答(2分钟版)

Raft 把分布式共识拆成三个子问题。Leader 选举:每个节点有随机超时,超时后转为 Candidate,term+1 发起投票,多数票当选。随机超时避免 split vote。日志复制:Leader 收到写请求后追加日志,并行发 AppendEntries 给 Follower,多数确认后提交。Follower 日志不一致时通过回退 nextIndex 对齐。安全性:投票时检查 Candidate 日志是否足够新,保证已提交日志一定在新 Leader 中。脑裂防护靠 term 递增——网络分区时旧 Leader 无法提交(没有多数派),新 Leader term 更大,恢复后旧 Leader 自动降级。和 ZAB 本质相同(Leader-based + 多数派),Raft 更通用、更易理解,etcd 和 Consul 都用 Raft。

追问与易错

追问方向:

  • “Raft 脑裂怎么解决?”→ term 递增 + 多数派,旧 Leader 无法提交,恢复后自动降级
  • “日志复制和提交的区别?”→ 复制是写到 Follower 磁盘,提交是多数确认后应用到状态机
  • “Raft 和 Paxos 优缺点?”→ Raft 易理解但强制 Leader(单点瓶颈),Paxos 理论更优但工程难实现
  • “Leader 宕机后数据会丢吗?”→ 已提交的不会丢(多数节点有),未提交的可能丢

易错点:

  • ❌ “两个 Leader 会脑裂”——term 大的有效,小的自动降级,不会同时有两个有效 Leader
  • ❌ “Leader 写完就算提交”——需要多数节点确认
  • ❌ “Raft 保证线性一致性读”——默认读 Leader 但可能读到旧数据(Leader 可能已过期),需要 ReadIndex 或 Lease Read 优化