从 Master / Slave 到路由系统

一次服务器集群治理的重构思考

在使用当前自研服务器框架的过程中,我反复遇到一个问题:

一旦业务涉及多节点协作,系统复杂度就会迅速上升。

最典型的场景,就是房间系统。

一、问题背景:房间系统的常见形态

在现有架构下,只要业务涉及:

  • 创建房间
  • 管理房间生命周期
  • 将房间分配到多个节点运行

最终几乎都会走向同一种设计:

为这个系统单独实现一套 Master + 多个 Slave

其中:

Master 负责

  • 决定房间运行在哪个节点
  • 路由请求
  • 维护节点状态 Slave 负责
  • 实际运行房间内部逻辑

这套模式本身并没有问题,但在工程实践中,它逐渐暴露出一些结构性缺陷。

二、现有模式的两个核心问题

  1. 重复造轮子

每一个需要“多节点协作”的系统,几乎都要重新实现一遍:

  • 节点管理
  • 心跳检测
  • 分配策略

这些逻辑高度相似,却分散在不同业务系统中,维护成本持续上升。

  1. 业务逻辑被架构细节侵入

理想状态下,业务开发只应该关心:

  • 房间如何创建
  • 房间内部逻辑如何运行

但在现实中,往往不得不理解:

  • 集群结构
  • 节点状态
  • 路由与容错策略

架构复杂度被直接暴露给业务层,降低了整体开发效率。

三、路由方案的讨论:取模与一致性 Hash

在尝试抽象统一的路由系统时,自然会讨论到常见的路由方案。

取模方案

取模方案具有以下特点:

  • 实现简单
  • 行为可预测
  • 性能开销低
  • 在节点数量相对稳定的前提下,这是一个成熟、可靠、工程上非常合理的方案。

一致性 Hash

一致性 Hash 的优势在于:

  • 节点变更时影响范围可控
  • 路由相对稳定

但同时也带来了更高的复杂度,通常需要配合数据迁移或状态控制机制。

需要强调的是:

一致性 Hash 并不一定“更高级”,它只是适用于不同的问题背景。

四、问题的本质,并不在路由算法本身

在讨论路由方案时,我曾提出过一个想法:

  • 系统已经运行较长时间,几乎没有发生过在线扩容、缩容或宕机恢复,
  • 是否可以在当前阶段,暂时不考虑数据迁移,换取更简单的路由实现。

这个想法最终被否定,技术负责人给出的建议是:

使用取模即可,不必引入更复杂的模块。

这是一个完全正确的工程决策。

但在这次讨论之后,我逐渐意识到:

  • 真正的问题,其实不在“用什么路由算法”,
  • 而在于系统并不知道集群当前到底处于什么状态。

五、现有 Monitor 机制的问题

回头分析当前系统获取集群状态的方式:

当前结构

  • 一个 monitor_master
  • 多个 monitor_slave

当前逻辑

  • 定期获取节点列表
  • 只要能获取到节点,就默认集群是正常的

这套机制存在明显隐患:

  • 只能确认节点“存在”
  • 无法判断节点之间是否仍然可通信

无法区分以下状态:

  • 扩容中
  • 缩容中
  • 宕机恢复中
  • 已经稳定

结果是:

路由系统只能假设集群始终稳定。

六、改进思路:引入集群版本号

针对这个问题,我设计了一个非常轻量但关键的改进方案。

核心思想只有一句话:

使用版本号,显式描述集群是否处于稳定状态

1. Slave 职责收敛

每个 monitor_slave 只负责上报自身信息:

  • 节点 ID
  • 当前状态
  • 心跳信息
  • 不参与任何集群状态判断。

2. Master 成为唯一裁决者

monitor_master 负责:

  • 检测 slave 心跳
  • 验证通信是否可达
  • 维护集群版本号

当发生以下事件时:

  • 节点新增(扩容)
  • 节点移除(缩容)
  • 节点宕机
  • 节点恢复

集群版本号自增。

3. 稳定态判定规则

当满足以下条件时:

  • slave 持有的版本号与 master 当前版本号一致
  • 且在一段时间内版本号没有变化

集群才被认为处于稳定状态。

七、路由系统开始具备“判断能力”

在集群状态可判定之后,路由系统不再只是一个简单的转发层。

集群稳定时

  • 可以使用取模
  • 也可以使用一致性 Hash

路由行为清晰、可预测

集群非稳定时

  • 拒绝创建新房间
  • 或延迟分配
  • 或进入降级策略

路由行为开始依赖于集群状态,而不是隐含假设。

八、最终目标:让业务开发回归业务

这次重构的目标,并不是引入某种复杂算法,而是:

  • 让业务开发只需要关注业务本身。

他们只需要关心:

  • 房间如何创建
  • 房间逻辑如何运行

而不需要关心:

  • Master 如何实现
  • Slave 如何管理
  • 集群是否真的稳定

九、总结

  • 取模是一种成熟且可靠的路由方案
  • 一致性 Hash 并非必须
  • 真正危险的不是算法简单,而是集群状态不透明
  • 一个简单的版本号机制,就能让系统从“假设稳定”走向“可判断稳定”

架构的价值,不在于复杂,而在于让复杂对业务不可见。

--完--