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

Q24: 如何设计广播机制?如何优化大规模广播?

核心结论

广播的本质不是“把一条消息发给很多人”,而是“在正确的范围、正确的时间、用合适的代价把信息分发出去”。

真正的大规模广播优化,第一步通常不是压榨网络库,而是先减少不该发的消息:

  • 不该看到的人不要发
  • 不重要的状态不要高频发
  • 不同消息不要用同一种广播策略

如果范围控制没做好,后面的压缩、批量、异步发送都只能止损,不能从根上解决问题。

一、先把广播分类型

广播至少可以分成四类:

1. AOI 内局部广播

例如:

  • 移动
  • 技能表现
  • 实体创建与销毁
  • 血量、朝向、Buff 变化

这是 MMO 最常见的一类,也是流量大头。

2. 逻辑域广播

例如:

  • 房间内广播
  • 队伍广播
  • 副本广播
  • 公会广播

它的接收范围通常是显式集合,不完全依赖空间位置。

3. 全局或大区广播

例如:

  • 系统公告
  • 跨服活动通知
  • 排行榜结算

这类消息频率低,但覆盖范围广。

4. 内部服务广播

例如:

  • 配置热更通知
  • 节点状态变化
  • 订阅事件分发

这类广播未必面向玩家连接,但同样会带来扩散成本。

广播要先分类,否则会把所有问题都错当成“网络发送优化”。

二、广播最大的成本来自哪里

很多人直觉上觉得广播瓶颈在 socket send,但工程里常见的大头其实是:

  • 接收者集合计算
  • AOI 查询
  • 序列化和拷贝
  • 多连接上的重复编码
  • 跨节点重复转发

尤其是位置和战斗状态广播,如果每次都重新查所有接收者、重新组包、逐连接编码,开销会很快失控。

三、优化第一原则:先缩小广播范围

1. AOI 裁剪

最基础也最有效。

只有真正看得到、需要知道该消息的玩家才应该收到。

这要求 AOI 系统不仅能回答“谁在附近”,还要能较低成本地维护:

  • 进入集合
  • 离开集合
  • 持续可见集合

2. 逻辑分组

队伍、房间、公会、战场等逻辑域不要每次临时扫描全服,应提前维护成员集合。

3. 按重要性降频

并不是所有状态都值得高频广播。

例如:

  • 位置和朝向高频
  • 血量中频
  • 属性面板低频
  • 非关键装饰状态更低频

如果所有字段都跟着位置同频率广播,带宽很快会爆。

四、优化第二原则:区分事件和状态

广播常常混着两类完全不同的内容:

  • 事件,例如施法、死亡、掉落、升级
  • 状态,例如位置、HP、朝向、当前动作

这两类消息适合的策略不同:

  • 事件更强调可靠送达和顺序
  • 状态更强调最新、可覆盖、可插值

如果用同一种可靠广播策略处理两者,要么状态广播过重,要么关键事件不够稳。

五、常见优化手段

1. 批量发送

在一个 tick 内,把多个小更新合并成一批再发,通常比每次变化立刻发更省:

  • 系统调用更少
  • 包头占比更低
  • 更容易做压缩

但批量窗口不能过大,否则会增加感知延迟。

2. 脏字段与增量同步

很多消息只改了少数几个字段,没必要整对象重发。

常见做法是:

  • 标记脏字段
  • 广播版本号或变化掩码
  • 客户端按字段合并

3. 多连接复用同一份编码结果

如果同一条广播要发给很多连接,不要对每个连接都重新序列化一遍。

更好的做法通常是:

  • 先编码一次共享消息体
  • 每个连接只补少量头部或引用

4. 分层转发

大范围广播不要总由单节点直推所有连接,常见做法是:

  • 先按场景、分区、网关分发
  • 再由边缘节点向本地连接扇出

这样更容易:

  • 降低跨机流量
  • 控制故障域
  • 缩短单点热点链路

六、AOI 广播为什么经常最难

因为它同时要求:

  • 高频
  • 低延迟
  • 范围动态变化
  • 接收者集合与空间位置强相关

一个移动事件触发后,系统往往不仅要广播位置变化,还要判断:

  • 哪些玩家新看到该实体
  • 哪些玩家看不到了
  • 哪些玩家仍在可见范围内

因此 AOI 广播优化往往要和 AOI 数据结构一起设计,而不是事后补丁。

七、大规模广播时如何避免风暴

1. 避免全服瞬时扇出

例如世界公告、活动开启通知,尽量不要让一个中心节点同步推给所有在线用户。

更稳妥的方式是:

  • 网关分层下发
  • 分片并行发送
  • 必要时做平滑扩散

2. 给广播做优先级

在发送队列拥塞时,应该明确哪些消息可以延后、合并甚至丢弃。

例如:

  • 关键事件优先
  • 高频位置更新可覆盖旧包
  • 非关键提示可降级

3. 控制背压

慢连接不能无限拖累发送队列。对明显跟不上的连接,系统需要具备:

  • 丢弃过期状态消息
  • 降频
  • 断开保护

否则一个少数慢连接就可能拖垮广播链路。

八、工程上常见的稳妥组合

很多 MMO 最后会收敛成类似策略:

  • AOI 内状态广播:增量加批量,位置类消息可覆盖旧版本
  • 关键战斗事件:可靠有序广播
  • 全局通知:分层转发
  • 网关侧:每连接队列和背压控制
  • 服务端:按场景或分区聚合接收者集合

重点始终是先分类型,再决定每类消息的频率、可靠性和传播范围。

九、常见误区

1. 广播优化就是消息压缩

压缩有用,但不是第一位。范围控制通常比压缩更重要。

2. 广播越实时越好

不对。很多低价值消息即使晚几十毫秒,对体验也没影响,却会显著增加系统成本。

3. 广播只和网络层有关

不对。AOI、数据建模、脏字段管理、网关分层、发送队列策略都会决定广播质量。

参考资料

  • Glenn Fiedler, Snapshot Compression / Snapshot Interpolation
  • 各类 MMO AOI 与广播系统设计实践资料
在 GitHub 上编辑此页
最后更新: 3/20/26, 6:06 AM
贡献者: cuihairu