从“全量快照”到“精细化属性同步”:WebSocket 大厅状态同步的极致演进

当一个多人联机游戏的大厅在线人数从 10 个人增长到 100 个人,再到 1000 个人时,最拉胯的性能瓶颈往往不是数据库,而是那个看似简单的“房间用户列表”和“游戏桌列表”的同步。

今天聊聊我们在 Game Hub 项目中对 WebSocket 大厅同步进行的三波“压榨式”重构。

1. 现状:全量广播的“地毯式”轰炸

最开始的实现非常直观:每当有玩家进入、离开或者准备,服务器就对这个分区的所有人广播一次完整的 UserListTableList

这种方案在人数较少时非常稳健,但缺点也极其明显:

  • 流量爆炸:100 个人在房间,一个人进来,发 100 份包,每份包里带 100 个人的信息。流量呈指数级上升。
  • CPU 抖动:频繁的大规模 JSON 序列化(甚至 Protobuf 全量序列化)对内存和 CPU 极不友好。

2. 第一波优化:增量同步模式 (Snapshot + Incremental)

我们引入了 “快照 + 增量” 的模式。核心思想类似于 Redis 的 AOF 或是视频编码的 I 帧/P 帧。

  • Snapshot (全量):用户第一次连入房间时,下发一次完整的数据。
  • Incremental (增量):后续只有在数据变动时,才发送 Upsert(更新/新增)或 Delete(删除)指令。

为了让这种模式在代码层面“长治久安”,我们封装了双端工具:

  • 后端 Go:设计了 SyncTracker 追踪器。它会标记哪些 ID 脏了,并在一个短的时间窗口(如 300ms)内自动去重,到期后执行 Flush
  • 前端 TS:提供统一的 mergeIncrementalItems 工具函数,强制执行 Object.assign 的同步规范。

3. 第二波优化:精细化字段更新 (Partial Updates)

即便有了增量同步,我们很快又发现了一个槽点。
如果一个玩家仅仅是切换了一个分区(Location),服务器依然会把他的 nickname, avatar_url, gold 等一大堆保持不变的数据重新发一遍。

这算哪门子增量?我们需要字段级的增量。

利用 Protobuf 3 的 optional 字段(在 Go 中体现为指针),我们实现了属性级的精细同步:

1
2
3
4
5
6
// 字段级精细同步协议
message GameTablePlayer {
int64 id = 1;
optional string nickname = 2; // 只在变动时赋值,其余为 nil
optional string location = 6;
}

在 Go 后端,赋值逻辑变得极度精简:

1
2
3
4
// 仅同步位置变更,包体瞬间从百字节降至十几字节
h.userTracker.MarkPartial(uID, &lobby.GameTablePlayer{
Location: &targetID,
})

4. 极致进化:自描述差量累积 (Partial Accumulation)

这是本次优化的点睛之笔。在 SyncTracker 的缓冲窗口期内,如果同一个玩家连续发生了多次属性变动,我们该如何处理?

我们利用了 proto.Merge 的特性。SyncTracker 内部维护的是一个局部差量对象。当新的变动到来时,不断与其执行 Merge
最终,在窗口结束时:

  • 所有变更被合并成了一个最小化的差异包。
  • 未变动的字段完全不占带宽。

配合前端的 ... (Spread Operator) 浅合并,这一套机制实现了**“空气级”**的流量开销:仅同步真正发生改变的那几个字节。

5. 战果与反思

经过这一套精细化大修,我们在大厅压测中得到了一组亮眼的数据:

  • 同步流量:在频繁切换分区的场景下,单次广播包体减小了 90% 以上。
  • 开发体验:利用 Protobuf 的强类型,代码从“拼掩码字段”变成了“直接操作 Partial Struct”,编译器成了最好的 Reviewer。

总结:架构设计的“硬约束”

这次优化让我最深刻的体会是:文档是靠不住的,唯有工具类能带来真正的规范。

我们没有写一份长达万字的《大厅同步协议优化指南》,而是直接将逻辑锁死在了 SyncTrackermergeIncrementalItems 这两个核心工具中。开发者只要想做同步,就必须按这套“精细化增量”的套路走。

“重构不仅仅是为了省那点流量,更是为了在未来增加第 100 个复杂状态属性时,大厅依然能像当初那样轻盈、丝滑。”


2026-03-31 记于二店长的游戏实验室


从“全量快照”到“精细化属性同步”:WebSocket 大厅状态同步的极致演进
https://erdianzhang.cn/2026/03/31/websocket-sync-optimization/
作者
兔特科技
发布于
2026年3月31日
许可协议