场景:玩家掉线重连
玩家在战斗过程中可能因网络波动、WiFi切换、隧道信号中断等原因短暂掉线。掉线期间,玩家的角色仍留在游戏世界中(可以被攻击、击杀),也可能被AI托管。玩家需要在重新连接后,尽快恢复到掉线前的完整状态(位置、血量、技能CD、Buff/Debuff、背包物品、任务进度等),并继续参与游戏。全服同时在线5000人,平均每小时约有5%~10%的玩家经历至少一次掉线重连。
约束
- 全服同时在线5000人,掉线率约5%~10%/小时
- 服务器心跳超时5秒判定为掉线,客户端心跳间隔2秒
- 玩家掉线后30秒内未重连,角色从场景中移除
- 重连时必须恢复:当前位置、血量/蓝量、技能CD剩余时间、Buff/Debuff列表、目标锁定状态
- 重连后技能CD必须延续掉线前的剩余时间,不能重置;掉线期间受到的伤害必须生效
- 重连时必须验证Token和Session ID,防止Session劫持
选型
方案一
redis存储玩家的session、token、网关、场景服的映射关系,这样在分布式架构下,就不用担心不同的机器都存储着玩家的session。心跳包更新时,也更新redis中session的ttl,保证其不过期。
当断线重连的时候,重新生成token、session,然后删除旧session和场景服的绑定关系。
重登后,如果玩家正在进行战斗,则优先同步战斗数据,例如血量、技能cd、回合数等。然后再异步同步背包、角色基础数据等。
角色如果在战斗过程中,掉线不会立刻删除角色,运行战斗逻辑的服务器的内存中存储战斗数据,这样重连后就可以直接获取最新的cd、血量,不用考虑快照和实际的误差。
优点:
- 适合分布式架构,不存在某个具体的服务存储玩家session、token、场景服的关系,有利于横向拓展。
- 内存存储战斗数据,避免了快照不一致的问题
劣势:
- 如果战斗很长,内存中可能会缓存很多数据,导致内存逐渐累积增长。
方案二
玩家的session、token都是服务器中缓存、重连后全量同步数据。
优点:
- 实现简单
劣势:
- 不利于横向扩展,因为服务器中直接缓存,
- 可能导致不同机器存储同个玩家的多个session,导致无法寻找到原始角色。
决策
采取方案一,理由:redis解耦session、token的存储,便于登录、网关等服务扩展。内存存储战斗数据,可以保证战斗数据不出现不一致。
容灾与异常处理
- 玩家数量较多时,可部署redis cluster,然后存储的session数据设置ttl,这样即使宕机了重启,超过ttl直接过期。
批改
选型批改
-
方案一(Redis+内存):
- 肯定:用Redis存Session/Token/路由映射是分布式标准做法;战斗数据存内存保证强一致;重连分优先级同步合理。
- 劣势补充:
- 内存泄漏风险:战斗服宕机会导致内存数据全丢,必须依赖快照兜底。
- 运维复杂度:引入Redis增加了网络开销和运维成本。
-
方案二:
- 批改:劣势分析准确(无法横向扩展、多Session冲突),适合单体架构但不适合当前5000人在线MMO。
决策理由批改
采取方案一。理由:Redis解耦Session实现横向扩展;内存存战斗数据保证强一致;重连分优先级同步保证体验。但需补充内存快照持久化以防战斗服宕机。
容灾与异常处理批改
- 原内容:仅提到Redis Cluster和TTL。
- 补充建议:
- 战斗服宕机:内存数据丢失,需从Redis/DB加载最近快照并回放离线期间日志。
- Redis宕机:依赖Cluster哨兵机制,TTL过期自动清理。
- 恶意刷CD:检测异常重连频率,触发则冻结账号。
- 快照落盘:内存快照定期异步写入Redis/DB。
方案优化
