《深入理解 Nacos 集群与 Raft 协议》系列
大家好,我是G探险者!
很多人部署 Nacos 集群时,会遇到这样一个问题:
我明明部署了 5 个节点,但只启动了 2 个,为什么系统完全无法使用?
这不是 Nacos 的 Bug,而是 Raft 共识算法的一个核心设计 ------ "过半存活原则"。
本篇我们将深入讲解:
- 为什么需要超过一半节点存活?
- 如果未过半,系统会发生什么?
- 如何从理论上理解这个约束?
一、Raft 的"过半投票原则"
Raft 在以下两个地方都要求"过半节点确认"才能推进:
- 选主(Leader Election):候选人需要获得超过半数节点投票才能成为 Leader
- 日志提交(Log Commitment):Leader 的日志条目,必须被超过半数节点确认,才能算"已提交"
这两个约束,是整个 Raft 一致性协议的核心。
→ 所以,没有过半节点存活,就选不出 Leader,无法提交日志,系统即不可用。
二、举例说明:三种典型节点数量
节点数 | 最小存活数(过半) |
---|---|
3 | 2 |
5 | 3 |
8 | 5 |
假设你部署了 8 个节点,只启动了 4 个,那就无法满足"超过 8/2 = 4"这个条件 → 系统无法进行任何写操作,甚至部分读操作也会失败(因为没有 Leader)。
三、为什么非得"过半"?
这是为了防止脑裂和数据丢失。
我们来思考一个问题:
如果 5 个节点中,A、B 两个节点单独启动,不满足过半,但系统仍允许它们工作,那会发生什么?
- A 成为了 Leader,写入一条日志(仅 A、B 有)
- 突然 A、B 宕机,C、D、E 启动,C 成为新 Leader
- C 重复写入了另一条日志(无 A、B 的写入)
→ 日志分叉!数据丢失!
为了避免这种情况,Raft 要求任何 Leader 的日志必须获得"过半副本确认",才能提交。
而一个节点想当选为 Leader,也必须能拿到过半选票。
所以,如果你活跃节点不满过半:
- 不能选主
- 原 Leader 无法继续领导(因心跳无响应)
- 所有提交机制暂停
→ 系统进入保护性停顿状态,而非错误工作。
四、Nacos 集群部署的建议
✅ 正确部署姿势
- 总节点数建议奇数(3、5、7、9),避免投票平票
- 启动时应确保至少过半节点在线,否则系统不工作
⚠️ 错误部署陷阱
- 部署 8 个节点,仅启动 4 个 → 失败
- 以为"部分可用" → 实则"不一致风险" → Raft 拒绝启动
五、可用性 vs 一致性
Raft 在设计时就做出了选择:
牺牲"部分可用性",换取"数据强一致性"
也就是说:
- 哪怕你能读取,但 Leader 不确定日志已同步 → 暂停处理
- 系统保证数据一致,而不是"不管三七二十一先返回"
这也是 Nacos、etcd、Consul 等注册中心使用 Raft 的原因:
- 配置信息必须强一致(否则灰度配置不生效)
- 服务列表变更必须可靠(否则服务发现错乱)
六、如何判断当前集群是否满足"过半"?
查看 Nacos 控制台日志或访问 /nacos/v1/ns/operator/raft/cluster
接口:
json
{
"leader": "nacos-1",
"raftPeers": [
{"ip": "nacos-1", "state": "LEADER"},
{"ip": "nacos-2", "state": "FOLLOWER"},
{"ip": "nacos-3", "state": "FOLLOWER"},
...
]
}
如日志中出现:
text
no leader is available now!
说明未能选主,系统已进入"挂起"状态。
七、总结
Raft 是为了保证数据一致性而牺牲了可用性的一种协议。
- 所有操作都要过半节点参与确认
- 未过半时,为防止脑裂,系统主动进入保护性不可用
- 在 Nacos 中体现为:Leader 无法选举、写请求挂起、读请求可能失败