遊戲 Lag 白皮書 › L7 伺服器 OS(kernel)
伺服器間連線的臨時 port 耗盡 Ephemeral port exhaustion (TIME_WAIT)
原因 ID so-ports · 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
在含圖解與實驗的完整版中開啟卡片 →
遊戲伺服器頻繁地對 DB 或其他伺服器建立又關閉短連線時,已關閉的連線會占用 port 一段時間,導致無法開啟新連線。
為什麼 每個請求都開啟再關閉一條新連線 → 於是 先關閉的一方會以 TIME_WAIT 狀態占用 port 約 60 秒(Linux),可用的 port 因此耗盡 → 畫面上 內部請求失敗,導致存檔失敗、功能異常
- 症狀
- 吃指令/回檔, 連不上/無限讀取
- 因素
- 遺失
- 誰會遇到
- 整個伺服器, 只有特定功能
- 何時
- 人潮湧入時
- 負責單位
- 主要負責 遊戲開發團隊(伺服器開發) · 協同 基礎設施團隊(伺服器基礎設施)
- 遊戲開發團隊要做的事
- 重複使用連線(連線池),不要每個請求都重新開關連線。
- 基礎設施團隊要做的事
- 擴大 port 範圍(ip_local_port_range)、評估對外連線重複使用 TIME_WAIT(Linux 的 tcp_tw_reuse)、監控 TIME_WAIT 數量。
- 數值參考
- Linux 的預設 port 範圍(32768~60999)約有 2 萬 8 千個。對同一個目的位址每秒建立超過 470 次新連線就會耗盡。Windows 的預設 port 約 1 萬 6 千個(49152~65535),TIME_WAIT 也更長,所以更快耗盡。
- 圖表上
- 碰到上限後持平 · TIME_WAIT socket 數、內部連線失敗次數
- 查看位置
- 用 ss -tan state time-wait 依目的位址計算 TIME_WAIT socket 數,並在遊戲伺服器 log 中找 connect 失敗(EADDRNOTAVAIL)
- 符合的跡象
- 連往同一目的地(DB 等)的 TIME_WAIT 在臨時 port 範圍(預設約 2 萬 8 千個)附近持平,connect 以 EADDRNOTAVAIL 失敗
- 不符合的跡象
- TIME_WAIT 不多,卻只有連往外部的連線失敗時是「雲端 NAT 閘道的連線與 port 上限」
- 確認方式
- 用基礎設施工具確認(不需要遊戲程式碼)
- 深入了解
- Linux 的 TIME_WAIT 60 秒是寫死在 kernel 裡的值。調低名稱相似的 tcp_fin_timeout 並不會縮短 TIME_WAIT。
出處
- IP Sysctl Linux kernel
ip_local_port_range 預設 32768~60999;tcp_tw_reuse;tcp_fin_timeout 是 FIN_WAIT_2 狀態的維持時間 - include/net/tcp.h (Linux v6.12) Linux kernel
TCP_TIMEWAIT_LEN(60*HZ):約 60 秒的 TIME_WAIT 是 kernel 常數 - TCP/IP port exhaustion troubleshooting Microsoft
Windows 動態 port 預設為 49152~65535,已關閉的連線預設會以 TIME_WAIT 占用 port 4 分鐘 - ss(8) — Linux manual page iproute2
以狀態篩選 state time-wait 只列出 TIME_WAIT socket - connect(2) — Linux manual page Linux man-pages
EADDRNOTAVAIL:臨時 port 範圍內的 port 全都在使用中,無法開啟連線
相關原因
同一層:L7 伺服器 OS(kernel)
同一症狀(吃指令/回檔)在其他層的原因
查看含圖解與實驗的完整版卡片