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

遊戲 Lag 白皮書 › L8 Socket 與協定

keepalive 預設值 2 小時 TCP keepalive defaults

原因 ID sk-keepalive · 主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發), 基礎設施團隊(伺服器基礎設施)

在含圖解與實驗的完整版中開啟卡片 →

對方沒有送出關閉訊號就消失時,TCP 要過很久才會察覺。keepalive(確認閒置連線是否仍存活的 TCP 功能)預設是關閉的,即使開啟,也要閒置 2 小時才開始確認。

為什麼 用戶端因斷電或線路中斷,沒有送出關閉訊號就消失 → 於是 伺服器認為連線仍存活(keepalive 預設 7,200 秒;若有正在傳送的資料,約 15 分鐘後才放棄重傳) → 畫面上 留下幽靈角色,重新連線時出現「帳號已登入」錯誤

症狀
連不上/無限讀取, 看不見/幽靈物件
因素
遺失
誰會遇到
只有我
何時
閒置一段時間後, 剛登入/維護剛結束
負責單位
主要負責 遊戲開發團隊(伺服器開發) · 協同 遊戲開發團隊(用戶端開發), 基礎設施團隊(伺服器基礎設施)
遊戲開發團隊要做的事
伺服器:回應心跳封包,一段時間沒收到就主動清理連線(調整 TCP_KEEPIDLE、TCP_USER_TIMEOUT);重新連線時用 session token 取代既有 session 並接續。用戶端:以數秒~數十秒的間隔(最短閒置逾時的一半以下)送出遊戲層級的心跳封包,斷線時自動重新連線。
基礎設施團隊要做的事
針對程式碼沒有自行設定的 socket,調低 kernel 預設值(tcp_keepalive_time 等)。只對開啟 SO_KEEPALIVE 的 socket 有效。
數值參考
Linux 的預設值是閒置 7,200 秒後開始確認,每隔 75 秒送出一次探測封包(probe),共 9 次,始終沒有回應就切斷連線。加起來約 2 小時 11 分鐘。Windows 預設也要閒置 2 小時才開始確認。
圖表上
只有部分偏高 · 每條連線距上次接收的經過時間
查看位置
用 ss -tnoi 看每條連線的 lastrcv(距上次接收的經過 ms)與 keepalive 計時器(timer:(keepalive,…)),並與遊戲伺服器「帳號已登入」的拒絕紀錄對照
符合的跡象
仍留有 lastrcv 達數分鐘~數小時的 ESTABLISHED 連線,且該帳號重新連線時以「帳號已登入」遭拒
不符合的跡象
沒有長時間沉寂的連線卻仍出現「帳號已登入」時,要查遊戲伺服器清理 session 的程式碼
確認方式
用基礎設施工具確認(不需要遊戲程式碼)

出處

  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 與協定

同一症狀(連不上/無限讀取)在其他層的原因

查看含圖解與實驗的完整版卡片