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

ゲームラグ白書 › TCP再送の根本原因

MTUブラックホール(大きいパケットだけ繰り返し失われる) PMTU black hole

原因ID rt-mtu · 主担当 インフラチーム・ネットワークインフラ · 副担当 インフラチーム・サーバーインフラ, ゲーム開発チーム・サーバー開発

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

途中の区間が受け取れるサイズが小さくなったのに「大きすぎる」という通知(ICMP)が遮断されると、大きなパケットは何度送り直しても消え続けます。

なぜ VPN・トンネル区間で最大サイズが小さくなり、サイズ超過の通知はファイアウォールで遮断 → すると 送信側は理由がわからないまま同じ大きなパケットを再送し続け、RTOは2倍ずつ増加 → 画面では 普段は問題ないが、インベントリ・人の多い場所・入場時のロードのように大きなデータがやり取りされる瞬間に、後続の小さなパケットまですべて止まり、最終的に切断や無限ロード

症状
フリーズ, 切断, 接続不可・無限ロード
要因
パケットロス
誰に起きるか
特定の地域・ISP, 自分だけ
いつ
特定の操作をしたとき, 接続直後・メンテ明け
担当
主担当 インフラチーム・ネットワークインフラ · 副担当 インフラチーム・サーバーインフラ, ゲーム開発チーム・サーバー開発
ゲーム開発チームの対応
サーバー側で直接下げるならソケットの最大セグメントサイズ(TCP_MAXSEG)を設定、ゲームコードでメッセージを細かく分割するだけでは防げない(TCPが送るデータをMSSのサイズでまとめ直すため)。
インフラチームの対応
ネットワーク:境界の機器でMSSを調整(clamping)、ファイアウォール・クラウドのネットワークACLでサイズ超過のICMP(タイプ3コード4、fragmentation needed)を許可。サーバー機器・OS:経路MTUの設定、サーバーのファイアウォール・クラウドのセキュリティグループでもサイズ超過のICMPが遮断されていないか確認、最後の安全策としてLinuxのtcp_mtu_probing=1。
数値の目安
通常は1,500バイトで、トンネルを通ると1,400前後です。同じパケットが5〜6回再送されると、止まる時間は10秒を超えます。
グラフでは
一部だけ高い · 接続ごとのRTO・backoff、地域・通信事業者ごとの切断数
確認箇所
問題の接続の再送をサーバー側のパケットキャプチャやbcc tcpretrans -s(シーケンス番号を表示)で確認し、ss -tiでその接続のmss・pmtu・backoffを確認。サーバーからそのユーザーのアドレスに、小さなpingとDFを立てた1,500バイトのping(ping -M do -s 1472)を送って比較
該当する場合
MSSいっぱいのパケットが同じシーケンス番号で、間隔を2倍ずつ延ばしながら再送され続け、それより小さなパケットは届く。サイズ超過のICMP(Wiresharkのフィルターicmp.type == 3 and icmp.code == 4)は届かず、小さなpingには応答があるのに、大きなDF付きのpingだけが応答なく消える
該当しない場合
小さなパケットも一緒に消えるなら、サイズと関係ないパケットロス(「ボトルネックでのキューあふれ」「経路変更・ECMPの不良経路」)。サイズ超過のICMPが届き、ss -tiのpmtuが小さくなるなら、経路MTU探索は正しく動作している
確認手段
インフラのツールで確認(ゲームコード不要)
もっと詳しく
tcp_mtu_probing=1は、再送タイムアウトが数秒(tcp_retries1=3に相当)続いた後になって初めてブラックホールと判断し、MSSを1,024バイトに下げます。その間は止まったままになるため、これは最後の安全策にとどめ、事前に防ぐMSSの調整を先に行います。

出典

  1. RFC 1191: Path MTU discovery IETF
    経路MTU探索:大きすぎるパケットはICMP「fragmentation needed and DF set」(タイプ3コード4)で通知
  2. RFC 2923: TCP Problems with Path MTU Discovery IETF
    ICMPが遮断され、大きなパケットだけが消え続けるPMTUブラックホールの問題
  3. RFC 4821: Packetization Layer Path MTU Discovery IETF
    ICMPを使わずにトランスポート層がパケットサイズを探る方法(Linuxのtcp_mtu_probingの土台)
  4. IP Sysctl Linux kernel
    tcp_mtu_probing:0は無効、1はブラックホールを検知したときだけ、2は常に(開始時のMSSはtcp_base_mss)。tcp_retries1のデフォルト値は3
  5. net/ipv4/tcp_timer.c Linux kernel
    RTOによる再送がtcp_retries1回続くとブラックホールを検知したとみなし、MTU探索を有効にしてMSSを下げる
  6. include/net/tcp.h Linux kernel
    TCP_BASE_MSS = 1,024バイト
  7. RFC 6298: Computing TCP's Retransmission Timer IETF
    再送タイマーが満了するたびにRTOを2倍に延ばす
  8. iptables-extensions(8) — Linux manual page netfilter
    TCPMSS --clamp-mss-to-pmtu:ICMPを遮断する区間のせいで大きなパケットが止まる問題を、SYNのMSSを調整して回避
  9. tcp(7) — Linux manual page Linux man-pages
    TCP_MAXSEG:送出するパケットの最大セグメントサイズ、接続前に設定すると相手に通知するMSSも変わる
  10. Network maximum transmission unit (MTU) for your EC2 instance AWS
    インターネットゲートウェイ・VPNはMTU 1,500、PMTUDにはICMPタイプ3コード4が必要で、セキュリティグループ・ネットワークACLが遮断すると受け取れない
  11. MTU considerations | Cloud VPN Google Cloud
    Cloud VPNゲートウェイのMTUは1,460バイト、IPv4トンネルのペイロードMTUは1,406バイト(トンネルを通ると1,400前後)
  12. Demonstrations of tcpretrans, the Linux eBPF/bcc version IO Visor
    再送ごとに1行ずつ表示し、-sは再送したパケットのシーケンス番号もあわせて表示
  13. ss(8) — Linux manual page iproute2
    ss -iのmss、pmtu(経路MTU)、backoff(RTOが2倍に延びた回数)
  14. ping(8) — Linux manual page iputils
    -M doはDFを立て、カーネルが把握している経路MTUより大きなパケットは送らない、-sはデータサイズ(ICMPヘッダーの8バイトは別)
  15. Display Filter Reference: Internet Control Message Protocol Wireshark
    icmp.type・icmp.codeの表示フィルター

あわせて読みたい原因

同じ層:TCP再送の根本原因

同じ症状(フリーズ)を起こすほかの層の原因

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