最近英雄联盟手游(LOLM)可以玩了,出于好奇,对其中一些体验到的技术点做了简单分析。以下猜测基于客户端观察与流量实测。
帧同步快速恢复
现象 游戏后台 60 秒后回到前台,花费 14 秒快速运算追上最新帧,录像中可以明显看到整个游戏世界被加速。60 秒按 60 帧制约 3600 帧,14 秒跑完意味着单帧运算压到约 3.8ms。
问题 若游戏已进行 20 分钟,按同样节奏恢复就需要约 4 分钟,体验相当差。由此引出两种可能的优化方向:
- 省略非必要计算恢复时省略不必要的流程(例如渲染),减小计算量、加快恢复速度。
- 服务端快照恢复服务端与客户端同步运算游戏逻辑(不只是广播帧操作),支持生成快照下发给客户端,客户端据此恢复,避免冗长的帧计算过程。
完全断线重连
现象 游戏进行 10 分钟时杀掉客户端进程,重新打开,从 loading 界面到能够继续游戏约 5 秒。
分析 1 — 对应猜测 1(省略非必要计算)
假设 4 秒跑逻辑、1 秒收网络消息。逻辑以 20 帧运行,10 分钟共 1.2 万帧,单帧逻辑运算开销约 0.41ms(测试设备 iPhone XS Max)。基于这个数字可以进一步推测实现方式:
- 重 C# 实现(可能性较高)如果是重 Lua 开发模式,0.41ms 极难达到。猜测用 C# 实现了绝大部分战斗逻辑。即便如此,0.41ms 已经非常出色。
- 多核并行 + ECS(有可能)若 CPU 8 核且充分利用多核,单帧总运算量约 3.28ms,更符合历史开发经验。要高效利用 8 核且方案可工程化,首选 ECS(面向数据编程)框架。
分析 2 — 对应猜测 2(服务端快照恢复)
若服务端下发了一帧的快照,客户端依据快照恢复,5 秒绰绰有余。快照恢复最难的部分是客户端需要 100% 还原数据,连 vector 中元素顺序都不能变。若采用服务端同步运算方案,可以获得几个关键收益:
- 极速结算服务端同步运算,结算时估计 1 秒内即可得出战斗结果。若非同步运算,服务端校验就需从头跑完整局(估算约 10 秒)。实际体验中,结束动画播完到显示结算不到 1 秒。
- 外挂检测服务端同步运算意味着可以每 5 秒对关键逻辑做信息摘要与服务器对比,检测帧同步一致性、及早发现不同步。帧同步本身对大多数外挂天然防御——客户端只上传操作,比较难防的主要是透视。
- 快照调试快照除了用于恢复,对帧同步一致性排查同样有帮助。结合信息摘要对比,内网开发版甚至可以在每个函数入口都生成摘要做对比,精准定位不同步发生在哪一次函数调用之后——类似调试中的断点功能。
佐证:AI 托管
玩家掉线或长时间未操作后,该玩家会被 AI 托管自动游戏。至少有两种实现方案:
- 服务端同步运算服务端拥有完整游戏逻辑,直接输出 AI 操作。
- 委托正常客户端服务端不运算,AI 委托给某个正常客户端输出操作并上报。
若全部玩家都掉线后 AI 仍在托管,方案 2 就被否定——这反向佐证了服务端拥有完整游戏逻辑的同步运算模型。
双通道网络通信
客户端与服务器之间使用 WiFi 与移动网络双通道同时通信,同一消息可以双通道下发、客户端按消息编号去重。对这种方案的具体做法,有三种猜测:
- 同一消息双通道同时下发每个包都在动态选择最优通道,以局部最优实现全局最优。代价:服务器出口流量翻倍、客户端网络 CPU 开销翻倍,并且消耗玩家的移动网络流量。
- 按敏感度分流帧消息走双通道,非帧消息(聊天、地图标记等)走单通道节省流量;也可只让某个通道走单号帧来降低开销。核心是在流量开销与玩家感受之间寻找平衡点。
- 重传时启用双通道正常时走单通道,判断需要重传时启用双通道尽最大努力重传,恢复后回归单通道。可引入"主通道"概念,实时根据网络质量动态选择。实现难度最大。
将三种猜测按关键代价维度横向对比如下:
| 方案 | 实现难度 | 服务器出口流量 | 客户端 CPU | 玩家移动流量 |
|---|---|---|---|---|
| 1 — 双通道同下发 | 低 | 翻倍 | 翻倍 | 高 |
| 2 — 按敏感度分流 | 中 | 仅帧消息翻倍 | 仅帧消息翻倍 | 中 |
| 3 — 按需启用(重传时) | 高 | 基本正常 | 基本正常 | 低 |
流量测算与实测
假设帧同步 20 帧/秒、10 人同场,单客户端上传流量最大约 0.48 kb/s,下载约 4.8 kb/s。10 分钟战斗下载流量约 2.8 MB。实测结果如下:
| 通道模式 | 时长 | 流量消耗 |
|---|---|---|
| WiFi 单通道 | 18 分钟 | 5 MB |
| 移动网络单通道 | 18 分钟 | 4.2 MB(杀进程重连额外 +4.4 MB) |
| 双通道 | 15 分钟 | WiFi 4 MB + 移动 2.8 MB |
关键发现 杀进程重连额外消耗约 4.4 MB,且游戏时间越长消耗越多——这几乎可以证明断线恢复是从第一帧重新运算到最新帧,而非基于快照恢复。结合实测流量,LOLM 的双通道方案更接近猜测 2 和猜测 3。
客户端登录请求频率限制
服务器处理登录请求的开销相比其他请求要大得多,瓶颈主要有三处:
- 数据加载从 DB 加载玩家数据到进程,Redis/MongoDB 较快,MySQL 更慢。
- SDK 验证平台账号验证通过 HTTP 处理。实测:异步 IO 处理 HTTP 约 2000 条/s,Redis 约 2 万条/s,公网通信约 1.5 万条/s。
- 登录后流量激增活动数据、商城信息、好友列表、邮件推送等,登录后几秒内持续消耗 CPU。
应对突发情况,登录排队和限制登录时间间隔都是可行方案。在架构设计上,若将不同类型请求微服务化,应对手段会更丰富——服务降级、弹性伸缩等。
弱网表现
TODO 原本想在 PC 上用模拟器抓包并模拟弱网来深入分析,但 LOLM 不支持 Android 模拟器。后续计划在 PC 上搭建代理服务器,让手机经由 PC 代理再连接游戏服务器,这样就可以在 PC 端抓包和模拟弱网了。