游戏卡顿白皮书 › L8 Socket 与协议
keepalive 默认 2 小时 TCP keepalive defaults
原因 ID sk-keepalive · 主责 研发团队·服务器开发 · 配合 研发团队·客户端开发, 运维团队·系统运维
在含图示和实验的完整版中打开此卡片 →
对方没发关闭信号就消失时,TCP 要过很久才能发现。keepalive(确认空闲连接是否还活着的 TCP 功能)默认关闭,开了也要空闲 2 小时才开始确认。
起因 客户端因断电、线路中断,没发关闭信号就消失了 → 结果 服务器认为连接还活着(keepalive 默认 7,200 秒。如果有正在发送的数据,约 15 分钟后才放弃重传) → 画面表现 留下幽灵角色,重新登录时报“已在线”错误
- 症状
- 连不上/无限加载, 隐身/幽灵实体
- 因素
- 丢包
- 谁会遇到
- 只有我
- 何时出现
- 挂机一段时间后, 刚登录/维护结束后
- 负责方
- 主责 研发团队·服务器开发 · 配合 研发团队·客户端开发, 运维团队·系统运维
- 研发团队要做的事
- 服务器:响应心跳,一段时间收不到就主动清理连接(调整 TCP_KEEPIDLE、TCP_USER_TIMEOUT);重新登录时凭会话令牌替换旧会话并接续。客户端:以几秒到几十秒的间隔(不超过最短空闲超时的一半)发送游戏层心跳;断开后自动重连。
- 运维团队要做的事
- 为代码没有单独设置的 socket 调低内核默认值(tcp_keepalive_time 等)(只对开启了 SO_KEEPALIVE 的 socket 生效)。
- 数值参考
- Linux 默认在空闲 7,200 秒后开始确认,以 75 秒间隔发送 9 次探测,始终没有响应就断开连接,合计约 2 小时 11 分钟。Windows 默认也要空闲 2 小时才开始确认。
- 监控图上
- 仅部分偏高 · 每个连接距最后一次接收的时长
- 查看位置
- 用 ss -tnoi 看每个连接的 lastrcv(距最后一次接收的 ms)和 keepalive 定时器(timer:(keepalive,…)),与游戏服务器的“已在线”拒绝记录对照
- 确认依据
- 存在 lastrcv 为几分钟到几小时的 ESTABLISHED 连接,且该账号重新登录时因“已在线”被拒
- 排除依据
- 没有长时间静默的连接却出现“已在线”,看游戏服务器的会话清理代码
- 确认手段
- 运维工具即可确认(无需游戏代码)
出处
- tcp(7) — Linux manual page Linux man-pages
空闲 7,200 秒后以 75 秒间隔探测 9 次(再多约 11 分钟);只对开启了 SO_KEEPALIVE 的 socket 生效;TCP_KEEPIDLE、TCP_USER_TIMEOUT - RFC 9293: Transmission Control Protocol (TCP) IETF
keepalive 默认必须关闭,空闲间隔默认值不低于 2 小时 - SO_KEEPALIVE socket option Microsoft
Windows TCP keepalive 默认超时 2 小时 - ss(8) — Linux manual page iproute2
-i 的 lastrcv(距最后一次接收的 ms),-o 的 timer:(keepalive,…)
相关原因
同一层:L8 Socket 与协议
其他层中同样导致“连不上/无限加载”的原因
查看含图示和实验的原卡片