《深入理解 Nacos 集群与 Raft 协议》系列五:为什么集群未过半,系统就不可用?从 Raft 的投票机制说起

《深入理解 Nacos 集群与 Raft 协议》系列

大家好,我是G探险者!

很多人部署 Nacos 集群时,会遇到这样一个问题:

我明明部署了 5 个节点,但只启动了 2 个,为什么系统完全无法使用?

这不是 Nacos 的 Bug,而是 Raft 共识算法的一个核心设计 ------ "过半存活原则"

本篇我们将深入讲解:

  • 为什么需要超过一半节点存活?
  • 如果未过半,系统会发生什么?
  • 如何从理论上理解这个约束?

一、Raft 的"过半投票原则"

Raft 在以下两个地方都要求"过半节点确认"才能推进:

  1. 选主(Leader Election):候选人需要获得超过半数节点投票才能成为 Leader
  2. 日志提交(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 无法选举、写请求挂起、读请求可能失败
相关推荐
Piper蛋窝3 小时前
深入 Go 语言垃圾回收:从原理到内建类型 Slice、Map 的陷阱以及为何需要 strings.Builder
后端·go
Bug退退退1234 小时前
RabbitMQ 高级特性之死信队列
java·分布式·spring·rabbitmq
prince055 小时前
Kafka 生产者和消费者高级用法
分布式·kafka·linq
六毛的毛5 小时前
Springboot开发常见注解一览
java·spring boot·后端
AntBlack5 小时前
拖了五个月 ,不当韭菜体验版算是正式发布了
前端·后端·python
31535669135 小时前
一个简单的脚本,让pdf开启夜间模式
前端·后端
uzong6 小时前
curl案例讲解
后端
菜萝卜子6 小时前
【Project】基于kafka的高可用分布式日志监控与告警系统
分布式·kafka
一只叫煤球的猫6 小时前
真实事故复盘:Redis分布式锁居然失效了?公司十年老程序员踩的坑
java·redis·后端
大鸡腿同学7 小时前
身弱武修法:玄之又玄,奇妙之门
后端