Raft 分布式一致性算法解析
Raft 是一种分布式一致性算法,由 Stanford 大学的 Diego Ongaro 和 John Ousterhout 于 2014 年提出,设计目标是替代 Paxos,解决 Paxos 难以理解和实现的问题。Raft 通过将一致性问题拆解为领袖选举(Leader Election)、日志复制(Log Replication)、安全性(Safety) 三个核心子问题,实现了更简洁、更易工程化的分布式一致性保障。
核心思想
Raft 是一种强领袖(Strong Leader) 算法:
- 集群中只有一个领袖(Leader) ,所有写操作必须通过 Leader 完成。
- Leader 负责将日志复制到所有跟随者(Follower) ,确保集群状态一致。
- 当 Leader 故障时,集群通过选举产生新的 Leader,保证服务不中断。
角色定义
Raft 集群中的节点有三种角色,角色会随集群状态动态切换:
| 角色 | 职责 |
|---|---|
| 领袖(Leader) | 处理所有客户端写请求,复制日志到 Follower,发起心跳维持领袖地位。 |
| 跟随者(Follower) | 被动接收 Leader 的日志和心跳,不主动发起请求。 |
| 候选人(Candidate) | 当 Follower 超时未收到心跳时,转为 Candidate 发起选举,争取成为 Leader。 |
关键机制
1. 任期(Term)
Raft 用任期(Term) 来划分时间,每个任期有一个唯一的整数编号(从 0 开始递增)。
- 任期是集群的逻辑时钟,用于判断节点的新鲜度(旧任期的 Leader 会被新任期的 Leader 取代)。
- 每个任期对应一次选举:如果选举成功,该任期内有一个 Leader;如果选举失败(如多个 Candidate 分裂投票),则进入下一个任期重新选举。
2. 领袖选举(Leader Election)
选举是 Raft 最核心的机制之一,触发条件是 Follower 超时未收到 Leader 的心跳(超时时间通常为 150-300ms,随机化避免同时发起选举)。
选举流程:
-
Follower → Candidate:Follower 超时后,自增任期号,转为 Candidate,向所有节点发送 RequestVote RPC(请求投票)。
-
投票规则:
- 节点在一个任期内只能投给一个 Candidate。
- Candidate 必须保证自己的日志至少和投票者一样新(日志的最后一条条目的任期号更大,或任期号相同但日志更长)。
-
Candidate → Leader:如果 Candidate 获得多数节点的投票,则成为 Leader,向所有节点发送心跳(AppendEntries RPC),维持领袖地位。
-
选举失败:
- 如果多个 Candidate 同时发起选举,可能导致分裂投票(无节点获得多数),此时所有 Candidate 超时后自增任期号,重新发起选举。
- 如果 Candidate 收到来自新 Leader 的心跳(AppendEntries RPC),则转为 Follower。
3. 日志复制(Log Replication)
Leader 负责将客户端的写请求转换为日志条目,复制到所有 Follower,确保集群状态一致。
日志结构:
- 每个日志条目包含:任期号(创建该条目的任期)、命令(客户端的写操作,如
set key value)、索引(条目在日志中的位置)。 - 日志必须满足:相同索引和任期的条目,内容相同;相同索引和任期的条目,之前的所有条目也相同(Leader 保证)。
复制流程:
- 客户端请求:客户端向 Leader 发送写请求。
- Leader 生成日志条目:Leader 将请求转换为日志条目,追加到自己的日志中。
- 发送 AppendEntries RPC:Leader 向所有 Follower 发送 AppendEntries RPC,包含新的日志条目。
- Follower 确认:Follower 收到日志条目后,追加到自己的日志中,向 Leader 发送确认(ACK)。
- 提交日志:当 Leader 收到多数节点的 ACK 后,标记该日志条目为已提交,并将命令应用到本地状态机,向客户端返回成功。
- 同步提交状态:Leader 在后续的心跳或 AppendEntries RPC 中,将已提交的索引告知 Follower,Follower 收到后将该条目应用到本地状态机。
4. 安全性(Safety)
Raft 通过以下规则保证安全性,核心是 “任何时刻,集群中只有一个 Leader,且 Leader 的日志是最新的” :
- 选举安全性:一个任期内只能有一个 Leader。
- 日志匹配:如果两个节点的日志在某个索引处有相同的任期号,则该索引之前的所有条目都相同。
- 领袖完整性:Leader 必须包含所有已提交的日志条目(通过投票规则保证,Candidate 必须日志足够新才能当选)。
- 状态机安全性:如果一个节点将某个日志条目应用到状态机,则其他节点不会在同一索引处应用不同的条目。
关键优化
-
日志压缩:
- 随着时间推移,日志会无限增长,Raft 提供快照(Snapshot) 机制压缩日志。
- Leader 将本地状态机的快照发送给 Follower,Follower 用快照替换旧日志,只保留快照后的日志条目。
-
增量日志复制:
- Leader 不需要每次发送完整日志,而是通过 AppendEntries RPC 的
prevLogIndex和prevLogTerm字段,只发送 Follower 缺失的日志条目。
- Leader 不需要每次发送完整日志,而是通过 AppendEntries RPC 的
-
只读请求优化:
- 对于只读请求,Leader 可以不写入日志,直接返回结果,但需要先确认自己的领袖地位(如发送心跳确认多数节点在线),避免旧 Leader 处理只读请求。
Raft 与 Paxos 的对比
| 特性 | Raft | Paxos |
|---|---|---|
| 设计目标 | 易理解、易实现 | 理论严谨、功能完备 |
| 核心思想 | 强领袖,分阶段处理 | 多阶段协商,无固定领袖 |
| 工程化难度 | 低(有大量成熟实现,如 etcd) | 高(难以实现正确的 Paxos) |
| 性能 | 写操作快(强领袖) | 写操作慢(多阶段协商) |
典型应用
Raft 是目前最流行的分布式一致性算法之一,广泛应用于:
- etcd:Kubernetes 的核心组件,用于配置管理和服务发现。
- Consul:服务网格和服务发现工具。
- Redis Cluster(部分特性):Redis 集群的主从复制和故障转移。
- TiDB:分布式关系型数据库,基于 Raft 实现数据一致性。
总结
Raft 的核心优势是简洁性和可实现性,通过将一致性问题拆解为领袖选举、日志复制、安全性三个子问题,降低了理解和实现的难度。其强领袖设计保证了写操作的性能,而任期和投票规则保证了安全性。对于分布式系统开发者来说,Raft 是必须掌握的一致性算法,也是面试中的高频考点。
是否需要我为你提供Raft 算法的核心 RPC 定义(RequestVote 和 AppendEntries) ,帮助你更深入地理解其通信机制?