한국어English日本語简体中文繁體中文DeutschไทยTiếng ViệtРусскийPortuguês (Brasil)EspañolBahasa Indonesia

游戏卡顿白皮书 › 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 连接,且该账号重新登录时因“已在线”被拒
排除依据
没有长时间静默的连接却出现“已在线”,看游戏服务器的会话清理代码
确认手段
运维工具即可确认(无需游戏代码)

出处

  1. tcp(7) — Linux manual page Linux man-pages
    空闲 7,200 秒后以 75 秒间隔探测 9 次(再多约 11 分钟);只对开启了 SO_KEEPALIVE 的 socket 生效;TCP_KEEPIDLE、TCP_USER_TIMEOUT
  2. RFC 9293: Transmission Control Protocol (TCP) IETF
    keepalive 默认必须关闭,空闲间隔默认值不低于 2 小时
  3. SO_KEEPALIVE socket option Microsoft
    Windows TCP keepalive 默认超时 2 小时
  4. ss(8) — Linux manual page iproute2
    -i 的 lastrcv(距最后一次接收的 ms),-o 的 timer:(keepalive,…)

相关原因

同一层:L8 Socket 与协议

其他层中同样导致“连不上/无限加载”的原因

查看含图示和实验的原卡片