5月28日 06:27

Consul 的 Raft 一致性协议是怎么工作的?

Consul 的 Server 节点通过 Raft 协议保证集群数据强一致性。所有写请求必须经过 Leader 处理,Leader 将操作写入本地日志后复制到多数 Follower,获得多数确认后提交——这就是"多数派"核心机制。一旦提交,这条日志就不会丢失,任何节点的状态机按相同顺序回放日志,结果一定一致。

Raft 把一致性问题拆成三个子问题:选主日志复制安全性。三个子问题各自独立但相互制约,共同保证最终一致。

选主:Follower 在选举超时内没收到 Leader 心跳,就自增 term 转为 Candidate,给自己投票并向其他节点发 RequestVote。拿到多数票的成为新 Leader。每个 term 只能投一票,先到先得——这就避免了分裂投票。关键约束:日志更完整的 Candidate 优先获得投票,保证新 Leader 一定包含所有已提交日志。

日志复制:Leader 收到客户端写请求后追加到本地日志,并行向所有 Follower 发 AppendEntries RPC。Follower 校验 prevLogIndex/prevLogTerm 是否匹配——匹配则追加,不匹配则拒绝,Leader 会回退逐条重试直到对齐。多数节点确认后 Leader 提交该条目,应用到状态机,响应客户端成功。

安全性:Raft 保证两条铁律——(1)已提交的日志永远不会被覆盖;(2)只有包含所有已提交日志的节点才能当选 Leader。这两条确保了任何时刻集群对外呈现的状态都是一致的。

追问

Leader 宕机后集群怎么恢复?

Follower 心跳超时触发选举,选出新 Leader 后,新 Leader 通过 AppendEntries 的日志匹配机制把落后 Follower 的日志补齐。如果旧 Leader 恢复,发现自己 term 更低,自动降为 Follower,截断未提交的日志。

网络分区时 Raft 怎么处理?

多数派分区继续正常服务(能选出 Leader、能提交日志),少数派分区无法获得多数确认,只能接收读请求(stale 模式)或直接拒绝。分区恢复后,少数派节点的未提交日志被 Leader 的日志覆盖。

Consul 的 Raft 和 etcd 的 Raft 有什么区别?

核心协议一样,工程实现不同:Consul 的 Raft 集成在 HashiCorp 的库中,支持多数据中心(每个 DC 独立 Raft 集群,DC 间走 WAN gossip);etcd 的 Raft 是独立库,支持 MVCC 和 watch 机制。性能调优参数也有差异——Consul 用 raft_multiplier 控制批量复制倍数,etcd 用 snap-count 控制快照阈值。

实际部署踩过什么坑?

节点数必须是奇数(3/5/7),偶数不增加容错能力反而增加选举复杂度。election_timeout 不能设太低,跨机房 RTT 波动容易触发误选举。曾经遇到 Server 磁盘 IO 慢导致日志写入延迟,心跳超时频繁切主——解法是给 Raft 数据目录用 SSD,并调大 heartbeat_timeout

写段代码

bash
# 查看 Raft 集群状态 consul operator raft list-peers # 移除故障节点 consul operator raft remove-peer -id=node3 # 关键配置 raft_protocol = 3 election_timeout = "1500ms" heartbeat_timeout = "1000ms" bootstrap_expect = 3 # 奇数节点
标签:Consul