遊戲 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 的程式碼
- 確認方式
- 用基礎設施工具確認(不需要遊戲程式碼)
出處
- 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 與協定
同一症狀(連不上/無限讀取)在其他層的原因
查看含圖解與實驗的完整版卡片