Apollo 技术文档Apollo 技术文档
指南
  • 架构概述
  • BigWorld 架构深度解析
  • BigWorld 进程架构与玩家生命周期
  • AOI九宫格系统详解
  • AOI广播与消息去重
  • Base 模块
  • Core 模块
  • Runtime 模块
  • Data 模块
  • Network 模块
  • /modules/actor.html
  • Game 模块
  • BigWorld 模块
服务器应用
API 参考
QA
GitHub
指南
  • 架构概述
  • BigWorld 架构深度解析
  • BigWorld 进程架构与玩家生命周期
  • AOI九宫格系统详解
  • AOI广播与消息去重
  • Base 模块
  • Core 模块
  • Runtime 模块
  • Data 模块
  • Network 模块
  • /modules/actor.html
  • Game 模块
  • BigWorld 模块
服务器应用
API 参考
QA
GitHub
  • MMORPG 架构 QA

Q8: 如何设计才能避免单点故障?

核心结论

避免单点故障,不是简单地把每个进程都复制一份,而是要回答四个问题:

  • 哪个组件一旦失效会影响核心链路
  • 这个组件有没有替代路径
  • 替代路径能否自动切换
  • 切换后的状态是否还能收敛

所以真正重要的不是“有没有单点”,而是:

  • 单点出现在哪里
  • 影响的是核心链路还是控制链路
  • 是必须彻底消除,还是可以接受短暂失效并快速恢复

一、什么才算真正的单点故障

单点故障不是指“只有一个实例”这么简单。

更准确地说,单点故障指的是:

系统中的某个组件或某类资源,一旦失效,而系统又没有有效替代路径,就会导致关键功能不可用。

这里有三个关键词:

  • 关键功能
  • 没有替代路径
  • 无法快速恢复

例如:

  • 只有一个登录入口,挂了后所有玩家都无法进入
  • 只有一个数据库主库,挂了后核心读写全部停止
  • 只有一个控制节点,挂了后拓扑无法调度
  • 只有一台交换机或一条链路,挂了后整个集群互相看不见

所以单点可以是:

  • 单进程
  • 单机器
  • 单数据库实例
  • 单网络设备
  • 单配置中心
  • 单机房
  • 单人工操作流程

最后一个经常被忽略。很多“技术上高可用”的系统,实际上切换还得靠人手工操作,那本质上仍然有运维单点。


二、不要把所有单点都当成同一类问题

在 MMO 架构里,单点至少可以分成四类。

2.1 接入层单点

例如:

  • 登录入口
  • 网关入口
  • 负载均衡入口

这类单点一旦失效,最直接的表现通常是:

  • 玩家无法登录
  • 新连接无法建立
  • 部分区服完全不可进入

2.2 控制面单点

例如:

  • BaseAppMgr
  • CellAppMgr
  • 调度器
  • 注册中心

这类单点失效时,系统往往不是立即全停,而是:

  • 动态调度失效
  • 新资源分配失败
  • 故障恢复能力下降
  • 长时间运行后风险累积

它们的特点是:

  • 对“持续治理能力”影响很大
  • 对“当前已有业务流”未必立刻致命

2.3 数据层单点

例如:

  • MySQL 主库
  • Redis 主节点
  • 唯一消息队列节点
  • 单一持久化代理

这类单点通常更危险,因为很多核心业务最终都要落到数据层:

  • 登录态
  • 角色数据
  • 交易
  • 邮件
  • 背包
  • 支付或订单

如果这里没有替代路径,影响往往很大。

2.4 基础设施单点

例如:

  • 单台物理机
  • 单交换机
  • 单电源
  • 单存储卷
  • 单机房

这类单点最容易被“进程多实例”掩盖。

比如你部署了三个服务实例,但都在同一台机器上,那对机器级故障来说,它们仍然是同一个单点。


三、判断是否是单点,不能只看实例数

一个很常见的误区是:

“我已经部署了两个实例,所以没有单点了。”

这不一定对。

更合理的判断方式是看故障域。

3.1 故障域是什么

故障域指的是“可能一起坏掉的一组资源”。

常见故障域包括:

  • 同一个进程
  • 同一台机器
  • 同一个机架
  • 同一个交换机
  • 同一个机房
  • 同一套存储
  • 同一个配置系统

3.2 典型伪冗余

以下情况看起来有冗余,实际上仍然存在单点:

  • 两个实例在同一台机器
  • 主备都依赖同一个配置中心
  • 多个服务都依赖同一个数据库主库
  • 两套系统共用同一条出口链路
  • 主备切换依赖同一个人工操作人

所以避免单点,本质上是在拆故障域,而不是只在进程数量上做加法。


四、MMO 架构里最需要优先处理哪些单点

不是所有单点都值得第一时间投入同样多的成本。

4.1 第一优先级:接入与数据

通常最应该优先处理的是:

  • 登录入口
  • 网关入口
  • 核心数据库
  • 核心缓存

原因很简单:

  • 它们直接影响玩家能否进入和能否完成核心操作
  • 一旦失效,影响面通常最大

4.2 第二优先级:会话与空间核心节点

例如:

  • 玩家会话节点
  • 地图逻辑节点
  • 关键空间调度节点

这类组件直接影响在线玩家体验,但处理方式通常要区分:

  • 实时逻辑节点更强调故障隔离和恢复策略
  • 控制节点更强调恢复和切换能力

4.3 第三优先级:后台和非核心功能

例如:

  • 排行榜
  • 统计
  • 日志归档
  • GM 后台

这类系统也不该是单点,但即便有单点,通常也可以优先采用“降级 + 快速恢复”,而不是一开始就做重型双活。


五、常见处理手段,但要分场景使用

5.1 多实例冗余

这是最基础的手段。

适合:

  • 登录服务
  • 网关服务
  • 无状态或弱状态服务

核心价值:

  • 单实例故障时,流量还能切到其他实例

但前提是:

  • 实例之间真的可替代
  • 客户端或上游知道如何切换
  • 状态不依赖本地唯一内存

5.2 主备切换

适合:

  • 控制节点
  • 数据节点
  • 有明确主从语义的组件

核心问题不是“有没有备”,而是:

  • 何时判定主挂了
  • 如何避免双主
  • 切换后谁负责重新收敛状态

5.3 自动重启与快速恢复

不是所有单点都必须彻底消除。

对于一部分控制面节点,更现实的策略是:

  • 接受它在短时间内是单点
  • 但把恢复时间做得足够短

这类策略适合:

  • 管理节点
  • 调度节点
  • 非核心写路径的后台节点

5.4 数据复制与故障转移

数据层不能只靠“进程自动拉起”。

通常还需要:

  • 主从复制
  • 故障检测
  • 读写切换
  • 数据校验

否则数据库虽然“恢复了”,但数据一致性可能已经出问题。

5.5 降级与熔断

有些单点无法完全消除,或者成本太高,这时就要设计降级路径。

例如:

  • 排行榜挂了,主游戏继续跑
  • 邮件延迟发送,交易主流程不被拖死
  • 聊天系统故障,不影响战斗和地图模拟

这也是避免“局部故障拖垮全局”的关键方式。


六、KBEngine / BigWorld 这类架构里怎么看单点

这类架构的典型特点是:

  • LoginApp / BaseApp / CellApp 往往可以多实例
  • 某些 manager 类组件天然更接近控制面单点
  • 数据层和基础设施层仍然可能存在真正的大单点

所以更准确的说法不是“哪个组件只有一个实例,所以它最危险”,而是:

  • 它失效时影响的是接入、实时逻辑、控制面,还是数据层
  • 它的状态能不能快速恢复
  • 它有没有替代路径

例如:

  • CellAppMgr 更像控制面单点
  • 数据库更像核心数据单点
  • 登录入口更像接入层单点

它们都重要,但处理方式不一样。


七、一个更务实的设计方法

7.1 先画关键链路

先把核心业务链路画出来:

  • 登录
  • 进入世界
  • 地图迁移
  • 交易
  • 角色保存

然后问:

  • 这条链路经过哪些组件
  • 哪个组件失效会中断整条链路
  • 有没有替代路径

7.2 再标记故障域

对每个关键组件标记:

  • 是否多实例
  • 是否跨机器
  • 是否跨机架或跨可用区
  • 是否共享同一数据库、存储、网络设备

7.3 最后做分级治理

一个更合理的优先级通常是:

  1. 先消除接入和数据层的硬单点
  2. 再处理会影响大面积在线体验的核心节点
  3. 最后处理控制面和后台系统的高可用优化

这比“所有组件都同时做成双活”更现实。


八、什么时候不该过度设计

很多项目在早期最容易犯的错误是:

  • 业务还没稳定
  • 监控还不完整
  • 自动化部署都没打稳
  • 就开始设计全链路双活、多机房、多主一致性

结果通常是:

  • 系统复杂度暴涨
  • 问题更难定位
  • 真实收益很有限

因此,避免单点故障不等于一开始就做最复杂的高可用架构。

更合理的做法通常是:

  • 先识别真正的硬单点
  • 先保证自动检测和自动恢复
  • 再根据业务规模逐步升级为主备、跨机房或更高级方案

九、一个更实用的检查清单

设计时可以直接问这些问题:

  • 登录入口是否只有一个
  • 核心数据库是否只有一个可写节点且无切换能力
  • 网关是否全部落在同一故障域
  • 关键 manager 故障后是否能自动恢复
  • 控制面故障时,数据面是否还能继续运行
  • 非核心功能故障时,是否会拖垮核心链路
  • 主备切换是否依赖人工
  • 监控、告警、演练是否已经建立

如果这些问题里有多个答案是“没有替代路径”,那系统里大概率就还有明显单点。


十、总结

避免单点故障的核心,不是“把所有东西复制两份”,而是:

  • 找到真正影响关键链路的故障点
  • 拆开故障域
  • 提供替代路径
  • 把切换和恢复做成自动化

对 MMO 来说,最应该优先关注的是:

  • 接入层单点
  • 数据层单点
  • 关键会话和空间节点的故障隔离
  • 控制面节点的恢复能力

一个成熟系统通常不是“没有任何单点”,而是:

即使某个局部失败,核心功能仍能继续,或者能在可接受时间内自动恢复。


参考资料

  • KBEngine Lab - Disaster Recovery
  • KBEngine GitHub
  • MySQL Replication
在 GitHub 上编辑此页
最后更新: 3/20/26, 6:06 AM
贡献者: cuihairu