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

ゲームラグ白書 › L7 サーバーOS(カーネル)

サーバー間接続のエフェメラルポート枯渇 Ephemeral port exhaustion (TIME_WAIT)

原因ID so-ports · 主担当 ゲーム開発チーム・サーバー開発 · 副担当 インフラチーム・サーバーインフラ

図と実験のあるメインページでこのカードを開く →

ゲームサーバーがDBやほかのサーバーへの接続を短時間で頻繁に張っては切ると、切れた接続がしばらくポートを占有し、新しい接続を開けなくなります。

なぜ リクエストごとに新しい接続を開いて閉じる → すると 先に閉じた側が約60秒(Linux)の間ポートを占有し(TIME_WAIT)、使えるポートが尽きる → 画面では 内部リクエストが失敗し、保存の失敗・機能のエラー

症状
不発・ロールバック, 接続不可・無限ロード
要因
パケットロス
誰に起きるか
サーバー全体, 特定の機能だけ
いつ
人が集中したとき
担当
主担当 ゲーム開発チーム・サーバー開発 · 副担当 インフラチーム・サーバーインフラ
ゲーム開発チームの対応
接続の再利用(コネクションプール)、リクエストごとに接続を開いて閉じないようにする。
インフラチームの対応
ポート範囲の拡大(ip_local_port_range)、外向き接続でのTIME_WAITの再利用(Linuxのtcp_tw_reuse)の検討、TIME_WAIT数の監視。
数値の目安
Linuxのデフォルトのポート範囲(32768〜60999)は約2万8千個です。同じ接続先に1秒あたり470回を超えて新しく接続すると尽きます。Windowsはデフォルトのポートが約1万6千個(49152〜65535)で、TIME_WAITも長いため、さらに早く尽きます。
グラフでは
上限で頭打ち · TIME_WAITソケット数、内部接続の失敗数
確認箇所
ss -tan state time-waitでTIME_WAITソケットを接続先アドレスごとに数え、ゲームサーバーのログからconnectの失敗(EADDRNOTAVAIL)を探す
該当する場合
同じ接続先(DBなど)へのTIME_WAITがエフェメラルポートの範囲(デフォルトで約2万8千個)付近で頭打ちになり、connectがEADDRNOTAVAILで失敗している
該当しない場合
TIME_WAITが少ないのに外部への接続だけが失敗するなら「クラウドのNATゲートウェイの接続・ポート上限」
確認手段
インフラのツールで確認(ゲームコード不要)
もっと詳しく
LinuxのTIME_WAITの60秒は、カーネルに固定された値です。名前の似た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):TIME_WAITの約60秒はカーネルの定数
  3. TCP/IP port exhaustion troubleshooting Microsoft
    Windowsの動的ポートのデフォルトは49152〜65535、閉じた接続はデフォルトで4分間TIME_WAITとしてポートを保持
  4. ss(8) — Linux manual page iproute2
    状態フィルターstate time-waitで、TIME_WAITソケットだけを絞り込んで表示
  5. connect(2) — Linux manual page Linux man-pages
    EADDRNOTAVAIL:エフェメラルポートの範囲のポートがすべて使用中で、接続を開けない

あわせて読みたい原因

同じ層:L7 サーバーOS(カーネル)

同じ症状(不発・ロールバック)を起こすほかの層の原因

図と実験のあるメインページでこのカードを見る