【テクニカル・上級編】 インターネットゲートウェイ経由の通信におけるMTU(Maximum Transmission Unit)制限 – クラウドインフラと仮想化ネットワーク実践ガイド

AWS VPCのパケット・パズル:MTU 1500の壁と「見えない断片化」の罠

クラウドアーキテクトとして数々の大規模トラフィックを捌いてきた経験から断言できるが、インフラのパフォーマンス問題の9割は、結局のところ「レイヤー2/3の整合性」に帰結する。

特にAWS VPC環境において、MTU(Maximum Transmission Unit)の理解を甘く見ているエンジニアは、高負荷時に突如として発生する「通信の蒸発」や「極端なスループット低下」という悪夢に直面することになる。今日は、なぜ標準的な 1500 バイトの壁が現代のクラウドにおいてクリティカルな制約なのか、そしてジャンボフレームとIGW(インターネットゲートウェイ)の深淵に潜む真実を紐解いていこう。

—

1. 1500バイトの呪縛とパケットの「断片化」という罪

AWSのVPCにおいて、EC2インスタンス間の標準MTUは 1500 バイトだ。これはイーサネットの黄金比であり、多くのネットワーク機器がデフォルトで採用している。しかし、現代のクラウドネイティブなワークロード、特にマイクロサービス間のgRPC通信や、巨大なオブジェクトを扱うデータパイプラインにおいて、この 1500 バイトはあまりに狭い。

もし、パケットが経路上のどこかでこの制限を超えると何が起きるか? 答えは「IPフラグメンテーション(断片化)」だ。

IPヘッダーにある DF (Don’t Fragment) フラグが立っているパケットが、MTUより大きなリンクを通過しようとすると、ルーターはパケットを破棄し、送信元に対して ICMP Type 3 Code 4(Destination Unreachable, Fragmentation Needed)を返す。これが有名な「PMTUD(Path MTU Discovery)」のプロセスだ。

問題は、現代のネットワークセキュリティ(セキュリティグループやNACL、あるいは過剰なファイアウォール設定)が、このICMPを「悪意あるパケット」とみなしてブロックしてしまうケースが非常に多いことだ。結果として、送信元と宛先は永久にハンドシェイクを完了できず、TCP接続は「接続中」のままフリーズする。これが「なぜか特定のAPIだけ疎通できない」というトラブルの典型的な正体である。

—

2. ジャンボフレーム(9001バイト)の甘い罠とIGWの現実

AWSは、サポートされているインスタンスタイプ間で 9001 バイトのジャンボフレームを許可している。これにより、1パケットあたりのヘッダーオーバーヘッドを削減し、CPUの割り込み頻度を劇的に下げることができる。

しかし、ここで一つ重要な注意点がある。IGW経由でインターネットへ出るパケットには、この 9001 バイトは適用されない、という点だ。

インターネット上の一般的なMTUは 1500 バイトである。VPC内部で 9001 バイトで処理されていた通信がIGWを通過し、インターネットの世界へ飛び出す際、AWSのゲートウェイは強制的に 1500 バイト以下への再構成(あるいは破棄)を試みる。もし、あなたのアプリケーションがジャンボフレームを前提にTCPウィンドウサイズを極端にチューニングしていたら、IGW通過時の急激なバッファ圧縮によってパケットロスが連鎖し、スループットはガタ落ちする。

実践:MTUの確認と調整(Linux)

まずは現在のインスタンスのMTUを確認しよう。

# インターフェースのMTUを確認
ip link show eth0 | grep mtu

# もしジャンボフレーム環境なら 9001 と表示されるはずだ

もし、特定のアプリケーションでPMTUDがうまく機能しない環境にあるなら、一時的な回避策としてMSS(Maximum Segment Size)クランプを行う。これはTCPハンドシェイク中にパケットサイズを強制的に制限する手法だ。

# iptablesによるMSSクランプの例
# TCP SYNパケットのMSSを1460に固定する
sudo iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1460

—

3. TLSハンドシェイクとバッファチューニングの最適化

MTUの問題は、TLSハンドシェイクの際にも牙を剥く。巨大な証明書チェーンを送信する際、パケットが断片化されると、中間ボックスでの再構築コストが増大する。

さらに、現代的なTLS 1.3ではハンドシェイクが高速化されているが、それでもTCPの「スロースタート」と「初期輻輳ウィンドウ(initcwnd)」の設定が甘いと、最初の数ミリ秒のRTT(Round Trip Time)で勝負が決まってしまう。

私は、高負荷なAPIサーバーを構築する際は、カーネルパラメータを以下のようにチューニングすることを推奨している。

# /etc/sysctl.d/99-network-tuning.conf

# TCP初期輻輳ウィンドウを10に設定(デフォルトの10であればそのままで良いが確認を)
# 接続開始直後のスループットを最大化する
net.ipv4.tcp_slow_start_after_idle = 0

# TCPウィンドウの自動チューニングを有効化
net.ipv4.tcp_window_scaling = 1

# メモリ割り当ての最適化
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216

—

4. 結び:エンジニアが向き合うべきは「目に見えない数値」

ネットワークのトラブルシューティングにおいて、「何が起きているか」を可視化することはプロの最低条件だ。IGWを通る際のMTU問題は、tcpdump でパケットのフラグメントビット(MFフラグ)を追うか、mtr でパケットロスが発生しているポイントを特定することで、その輪郭が見えてくる。

# インターネットへのパケットを追跡し、フラグメント化を疑う
sudo tcpdump -ni eth0 'ip[6] & 0x20 != 0 or (ip[6] & 0x40 != 0)'
# 注: これは断片化されたパケットをキャプチャするフィルタリング例

クラウドの恩恵を最大限に受けるには、抽象化されたGUIコンソールから一歩踏み出し、カーネルがパケットをどう扱い、TCPがどのようにウィンドウを広げているのか、その「鼓動」を感じ取ることが重要だ。

MTUの 1500 という数字は、決して単なる定数ではない。それは、世界中のネットワークが互いに妥協し合っている「平和の調停値」なのだ。その調停を乱すとき、我々エンジニアは、パケットの行く末に責任を持たなければならない。

コメント

タイトルとURLをコピーしました