引言:为什么需要共识算法?
在分布式系统中,节点可能崩溃、网络可能分区、消息可能丢失。面对这些故障,如何让多个节点就某个值达成一致?这正是共识(Consensus)算法要解决的核心问题。从 Paxos 到 Raft,从 ZAB 到 Gossip,共识算法是分布式系统的基石。
Raft 算法由 Diego Ongaro 和 John Ousterhout 在 2014 年的论文《In Search of an Understandable Consensus Algorithm》中提出。相比 Paxos 的"难以理解",Raft 通过"分离"策略——将共识问题拆分为 Leader 选举、日志复制和安全性三个相对独立的子问题——大幅降低了理解和实现的门槛。如今,Raft 已被广泛应用于 etcd、TiKV、Consul、CockroachDB 等生产级系统中。
本文将从 Raft 的核心原理出发,逐步深入到 Rust 工程实现,最终构建一个支持线性一致性的分布式键值存储。
一、Raft 基础:Term 与角色状态机
1.1 任期机制(Term)
Raft 将时间划分为一个个连续的任期(Term),每个 Term 是一个单调递增的整数。Term 是逻辑时钟,用于标识数据的"新旧"——拥有更高 Term 的节点始终被视为更权威。每个节点维护 current_term,并在 RPC 通信中携带 Term 信息:
当节点收到 RPC 请求或响应时:
if args.term > current_term:
current_term = args.term
role = Follower // 立即降级为 Follower
voted_for = None // 清除投票记录
13种角色与状态
Raft 中每个节点在任意时刻只扮演三种角色之一:
- Leader:唯一处理客户端请求的节点,负责日志复制给所有 Follower
- Followers:被动接收 Leader 的心跳和日志,超时则转为 Candidate
- Candidate:发起投票试图成为 Leader,获得多数票后晋升为 Leader
状态转移图核心规则:
Follower → Candidate: election_timeout 超时(通常 150-300ms 随机化)
Candidate → Leader: 获得同一 Term 中多数节点(N/2 1)的投票
Leader → Follower: 发现更高 Term 的请求或响应
Candidate → Follower: 发现更高 Term 或合法 Leader 的心跳
二、Leader 选举:多数派投票机制
2.1 选举触发与投票流程
当 Follower 在 election_timeout 内未收到 Leader 心跳时,它自增 Term、转为 Candidate、先投自己一票,然后向所有其他节点发送 RequestVote RPC。
每个节点在每个 Term 内最多投给一个 Candidate(先到先得原则),投票请求中包含 Candidate 的最后日志索引和 Term,以确保"日志至少一样新"的节点才能当选:
class RequestVote:
term: u64 // Candidate 的 Term
candidate_id: u64 // Candidate 的节点 ID
last_log_index: u64 // Candidate 最后日志的索引
last_log_term: u64 // Candidate 最后日志的 Term
投票拒绝条件(满足任一即拒绝):
1. args.term < current_term
2. voted_for 不为空且不等于 candidate_id
3. Candidate 的日志不如本节点更新(比较最后日志的 Term;Term 相同则比较 index)
2.2 选举超时随机化
多个 Follower 同时超时会引发"split vote"(平票),导致多次选举失败。Raft 通过让每个节点在 [150ms, 300ms] 范围内随机选取超时时间,大幅降低了并发选举冲突的概率。实践中,3 节点集群的首轮选举成功率

发表评论 取消回复