为什么需要共识算法?

在分布式系统中,多节点之间的"达成一致"是最核心也最困难的问题。当三台服务器需要在某个值上达成共识——无论是数据库写入命令、配置变更指令,还是分布式锁的获取——都必须保证:只有当一个值被选定后,所有节点最终都会接受它,且永远不会被篡改。

这就是共识(Consensus)问题。而 Raft 算法的诞生,就是为了给这个经典难题提供一个可理解、可实现、可验证的工业级解决方案。

相比 Paxos 的"学术优雅但工程艰涩",Raft 采用了"强领导者(Strong Leader)"模型,将共识过程分解为三个相对独立的子问题:

  1. 领导者选举(Leader Election):选出唯一的决策者
  2. 日志复制(Log Replication):将决策同步到多数节点
  3. 安全性(Safety):确保已提交日志永不丢失

三个子问题层层递进,构成了 Raft 的完整故事。

基础架构:术语与状态模型

节点角色

Raft 集群中每个节点始终处于以下三种角色之一:

  • Leader:处理所有客户端请求、驱动日志复制,每个任期至多一个
  • Follower:被动接收 Leader 的心照不宣与日志条目,超时未收到心跳则转为 Candidate
  • Candidate:发起选举投票、争取成为 Leader,获得多数票则成为 Leader

正常工作时,一个 Leader + 多个 Follower。Leader 定期发送心跳维持权威。当 Follower 在选举超时窗口内未收到心跳,它就认为 Leader 宕机,开始新一轮选举。

时间模型:Term(任期号)

Raft 将全局时间划分为连续的任期(Term),每个任期由一个严格递增的整数标识。任期是逻辑时钟:

  • 每个节点维护 current_term,遇到更高任期号时立即更新
  • 每个任期至多有一个 Leader
  • 某些任期可能没有 Leader(选举分裂导致)
  • 节点间通信时携带任期号:任何节点如果发现自己的任期过期,立即退为 Follower

第一阶段:领导者选举

选举触发机制

每个 Follower 维护一个随机化的选举超时(通常 150ms ~ 300ms)。当超时到期且未收到 Leader 心跳时:

  1. 递增 current_term
  2. 转为 Candidate
  3. 投给自己一票
  4. 向所有节点发送 RequestVote RPC
  5. 重置选举超时(随机值,降低再次分裂概率)

随机化超时的核心目的:防止多个节点同时发起选举导致选票分裂。如果所有 Follower 同时超时,必然分裂;随机化使得各节点超时时间错开,第一个超时的节点大概率在其他人超时前赢得选举。

投票规则(关键安全性约束)

接收者只有在以下两个条件同时满足时才会投票:

  1. Candidate 的日志至少和接收者一样新:比较 (last_log_term, last_log_index) 字典序
  2. 接收者在本任期内尚未投票给其他人(voted_for 为 None 或就是该 Candidate)

"日志至少一样新"的规则防止了已提交日志的丢失:一个日志较旧的节点永远无法赢得选举。

第二阶段:日志复制

基本流程

Leader 处理客户端请求的完整路径:

  1. 追加:Leader 将命令作为新日志条目追加到本地 log
  2. 广播:Leader 并行向所有 Follower 发送 AppendEntries RPC
  3. 确认:Follower 复制成功后返回 success: true
  4. 提交:Leader 收到多数确认后,递增 commit_index,应用到状态机
  5. 通知:下一次心跳携带新的 commit_index,Follower 依次应用

日志冲突的快速回退优化

当 Follower 的日志与 Leader 不一致时,Raft 使用 Term-based 快速回退策略:Follower 在自己日志中找到冲突 Term 的第一条索引告知 Leader,直接回退到该 Term 之前的日志,大幅减少试错轮次。

第三阶段:安全性与正确性证明

选举安全性(Election Safety)

每个任期内至多有一个 Leader。每个节点每个任期只能投一票,只有获得多数票才能成为 Leader。多数集交集保证:任何两个多数集至少共享一个节点。

Leader 完备性(Leader Completeness)

一旦一条日志条目被提交,所有更高任期的 Leader 的日志中一定包含该条目。这依赖于投票规则保证:复制多数集与投票多数集必有重叠,因此 Leader 必定持有已提交条目。

No Committing Before the Current Term

这是 Raft 与 Paxos 最大的工程差异之一。即使有"被多数复制"的直接证据,如果是旧任期的日志也不能直接提交。这是防止"幽灵复现"的关键保障。

生产级工程优化

日志快照(Snapshotting)

长时间运行的 Raft 集群日志无限增长,Leader 定期创建状态机快照,通告 Follower 安装快照(InstallSnapshot RPC),安装完成后删除对应日志条目。

集群成员变更

使用联合共识(Joint Consensus)或单节点变更策略,保证任何时刻不会存在两个不相交的多数决议。etcd、TiKV 等系统采用主流的单节点变更方案。

线性一致性读

Read Index(等待 commit_index 追上)、Lease Read(心跳租约期内直读)、Follower Read(向 Leader 确认 commit_index 后读)三种方案保障。

性能关键优化

  • Pipeline 复制:不等返回就发送下一个
  • Batch 合并:多条目合并为一个 RPC
  • Learner 节点:新节点先追赶日志再转 Voter
  • Pre-Vote:正式递增 Term 前先探测多数可达
  • 检查点提示:快速回退 hint 减少冲突重试

Raft vs Paxos vs ZAB

  • Raft:可理解性优先,强 Leader,etcd/TiKV/CockroachDB
  • Paxos:数学优雅但工程模糊,Chubby/Spanner
  • ZAB:ZooKeeper 私有协议,KV 存储优化

总结

Raft 的核心设计理念是可理解性优先,但安全性不打折扣:

  1. 持久化三项:current_term、voted_for、log[] 每次响应前落盘
  2. 提交条件:只提交当前任期的、被多数复制的条目
  3. 随机超时:选举超时随机化避免选票分裂
  4. 日志一致性:prev_log_index + prev_log_term 保证对齐
  5. 安全第一:成员变更一次一个节点或使用联合共识
  6. 快照不可或缺:长期运行必须配合快照压缩

从 etcd 到 TiKV,从 Consul 到 CockroachDB,Raft 已成为现代分布式系统的"事实共识标准"。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部