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

遊戲 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。

出處

  1. IP Sysctl Linux kernel
    ip_local_port_range 預設 32768~60999;tcp_tw_reuse;tcp_fin_timeout 是 FIN_WAIT_2 狀態的維持時間
  2. include/net/tcp.h (Linux v6.12) Linux kernel
    TCP_TIMEWAIT_LEN(60*HZ):約 60 秒的 TIME_WAIT 是 kernel 常數
  3. TCP/IP port exhaustion troubleshooting Microsoft
    Windows 動態 port 預設為 49152~65535,已關閉的連線預設會以 TIME_WAIT 占用 port 4 分鐘
  4. ss(8) — Linux manual page iproute2
    以狀態篩選 state time-wait 只列出 TIME_WAIT socket
  5. connect(2) — Linux manual page Linux man-pages
    EADDRNOTAVAIL:臨時 port 範圍內的 port 全都在使用中,無法開啟連線

相關原因

同一層:L7 伺服器 OS(kernel)

同一症狀(吃指令/回檔)在其他層的原因

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