Raft 分布式共识算法详解:从选举到日志复制

举报
yd_236430038 发表于 2026/10/25 21:37:51 2026/10/25
【摘要】 Raft 分布式共识算法详解:从选举到日志复制本文深入剖析 Raft 共识算法的核心原理,帮助你理解分布式系统如何达成一致性。 为什么需要共识算法?分布式系统中,多个节点需要就某个值达成一致,但面临:┌─────────────────────────────────────────────────────────┐│ 1. 节点可能崩溃(Crash Fault) ...

Raft 分布式共识算法详解:从选举到日志复制

本文深入剖析 Raft 共识算法的核心原理,帮助你理解分布式系统如何达成一致性。

为什么需要共识算法?

分布式系统中,多个节点需要就某个值达成一致,但面临:

┌─────────────────────────────────────────────────────────┐
│  1. 节点可能崩溃(Crash Fault)                          │
│  2. 网络可能分区、延迟、丢包、乱序                       │
│  3. 消息可能重复                                        │
│                                                         │
│  但假设:不存在恶意节点(非拜占庭容错)                  │
└─────────────────────────────────────────────────────────┘

共识算法目标: 即使部分节点故障,系统整体仍能对外提供一致、可用的服务。

典型应用: etcd、Consul、TiKV、CockroachDB、Kafka KRaft。

Raft 的核心思想:可理解性优先

Raft 把共识分解为三个相对独立的子问题:

1. Leader 选举(Leader Election)
2. 日志复制(Log Replication)
3. 安全性(Safety)

核心准则:任何时刻最多一个 Leader,
所有写入都经由 Leader 发起并复制到多数节点。

节点角色与任期

┌─────────────────────────────────────────────────────────┐
│  三种角色                                               │
│                                                         │
│   Follower ──超时未收心跳──→ Candidate ──获多数票──→ Leader │
│      ↑                                              │    │
│      └──────────────── 收到更高任期 ───────────────┘    │
│                                                         │
│   Term(任期):单调递增的逻辑时钟,用 term 号区分         │
│   不同选举周期,是判断信息新旧的核心依据                   │
└─────────────────────────────────────────────────────────┘

角色职责:

角色 职责
Leader 接收写请求,复制日志,发送心跳
Follower 被动接收日志和心跳,超时则发起选举
Candidate 发起投票,争取成为 Leader

Leader 选举

选举触发与流程

选举超时(Election Timeout):随机 150ms ~ 300ms

Follower 超时未收到心跳:
  1. 自增 term,转为 Candidate
  2. 投票给自己
  3. 向所有节点发送 RequestVote RPC
  4. 获多数票(N/2 + 1)→ 成为 Leader
     若无多数票 → 超时后再次发起新选举

┌─────────┐  RequestVote   ┌─────────┐
│Candidate│ ──────────────→│Follower │
│ term=2  │ ←──────────────│  投票   │
└─────────┘   RequestVote   └─────────┘

随机超时的作用

问题:若所有 Follower 同时超时,会瓜分选票导致无人过半(选票分裂)

解决:每个节点随机选举超时时间
  → 大多数情况下只有一个节点先超时成为 Candidate
  → 大幅降低选票分裂概率,即使分裂下次也能快速收敛

投票规则

Follower 投票给 Candidate 的条件(同时满足):
  1. term 不小于自己当前 term(否则拒绝)
  2. 自己本任期尚未投票
  3. Candidate 的日志"至少不比自己旧"
     (最后日志的 term 更大,或 term 相同但 index 更大)

→ 保证选出拥有最全日志的 Leader(安全性关键)

日志复制

正常流程

Client ──写请求──→ Leader
                    │
                    ├─ 1. 追加到本地日志(uncommitted)
                    ├─ 2. 并行发送 AppendEntries 给所有 Follower
                    ├─ 3. 多数 Follower 写入成功
                    ├─ 4. Leader 提交(commit)并返回客户端
                    └─ 5. 通知 Follower 提交

日志结构:
  index:  1     2     3     4     5
  term:   1     1     2     2     3
  cmd:   x=1  y=2  x=3  y=4  x=5

AppendEntries RPC 与一致性检查

AppendEntries 携带:
  - term:Leader 任期
  - leaderCommit:Leader 已提交位置
  - prevLogIndex / prevLogTerm:前一条日志的位置与任期
  - entries[]:要复制的日志

一致性检查:
  Follower 校验 prevLogIndex 处的日志 term 是否匹配:
  - 匹配:接受新日志
  - 不匹配:拒绝,Leader 递减 nextIndex 重试
  → 逐条回溯,最终找到一致点,覆盖冲突日志

提交规则(安全性核心)

Leader 只能提交"当前任期"的日志!

关键限制:
  即使旧任期日志被复制到多数节点,也不能仅凭副本数提交,
  必须等当前任期有一条日志被复制到多数节点后,
  才能连带提交之前的旧日志(commitIndex 前移)。

原因:避免"已提交日志被回滚"的悖论。
(论文中的 Figure 8 场景)

网络分区与脑裂处理

场景:5 节点分区分裂

  分区 A(3 节点):有 Leader,可正常选举与提交
  分区 B(2 节点):旧 Leader 无法获多数,无法提交

┌───────────────┐        ┌───────────────┐
│  分区 A       │        │  分区 B       │
│  ● ● ●  (3)   │   ╳    │  ● ●  (2)     │
│  有多数,正常 │        │  无多数,阻塞 │
└───────────────┘        └───────────────┘

恢复后:
  分区 B 中 term 较低的节点收到更高 term → 回退为 Follower
  冲突的未提交日志被 Leader 覆盖 → 系统重新一致

结论:多数派(Quorum)是可用性的分界线
  5 节点容忍 2 个故障,3 节点容忍 1 个故障

成员变更与日志压缩

成员变更

问题:直接切换配置可能产生"双多数派",出现两个 Leader

解决(单节点变更法):
  每次只增/删一个节点,保证任意时刻新旧配置多数派有交集
  → 不会同时选出两个 Leader

日志压缩(Snapshot)

问题:日志无限增长,重启回放慢

解决:Snapshot(快照)
  1. 将当前状态机的状态持久化为快照
  2. 快照覆盖 index 之前的日志可丢弃
  3. 新节点通过 InstallSnapshot RPC 快速同步

  index: 1..1000  → Snapshot(状态) + 日志[1001..]

对比 Paxos

维度 Raft Paxos
设计目标 可理解性、工程友好 理论优雅
Leader 强 Leader,日志单向流动 弱化,多变体
日志 连续、强一致复制 允许空洞
教学/实现 易于理解和实现 晦涩,实现多样
代表 etcd、TiKV Chubby、Spanner

实战:生产环境要点

# etcd 集群健康检查
etcdctl endpoint health --cluster
etcdctl endpoint status --cluster -w table

# 关键监控指标
# - leader 变更频率(频繁说明网络或负载异常)
# - 日志复制延迟
# - WAL fsync 延迟(磁盘是常见瓶颈)

部署建议:

  1. 节点数用奇数:3 或 5,兼顾容错与性能
  2. 跨机架/可用区部署:避免同故障域,但也别过度分散导致延迟高
  3. SSD 存储:WAL fsync 对磁盘延迟敏感
  4. 网络稳定:高延迟会触发频繁选举,影响可用性
  5. 监控选举与复制延迟:及时发现问题

总结

子问题 核心机制
选举 随机超时 + 多数投票 + term 比较
日志复制 AppendEntries + 一致性检查 + 覆盖冲突
安全性 只提交当前任期日志;投票限制日志新旧
容错 多数派(Quorum),容忍 N/2 故障
变更 单节点变更避免双多数派

Raft 的精髓:用强 Leader 简化问题,用随机化和多数派保证安全,用 term 和日志匹配保证一致。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。