深夜3時のアラート音。これほどインフラエンジニアの胃をキリキリさせる音はない。
「ある特定のAPIエンドポイントに対して、大容量のJSONをPOSTすると、なぜかコネクションがタイムアウトする」「特定の拠点からだけ、クラウド上のリソースへ接続できないパケットロスが発生している」。
こうした現場の修羅場で、若手エンジニアから「先生、pingは通るんですけど、アプリケーション層の通信だけ死んでます」という報告を受けるたび、私はこう問い返す。
「それ、ペイロードのサイズとDFフラグを意識したか?」と。
教科書通りのpingを打って「ロス率0%だからネットワークは正常です」なんて報告しようものなら、百戦錬磨のNOCチームから総ツッコミを受けること確実だ。パケットは目に見えない。だからこそ、CLIコマンドが発する微弱なシグナルを読み解き、ルーターやスイッチ、そしてインターネットの海を渡るパケットの「実際の振る舞い」を脳内でビジュアライズできなければ、現代の複雑なクラウド&Webインフラを生き抜くことはできない。
今回は、ネットワークトラブルシューティングの基本にして奥義、pingのデータペイロードとMTU(Maximum Transmission Unit)、そしてDF(Don’t Fragment)フラグが織りなすパケットの深淵へあなたを案内しよう。
—
1. なぜ「普通のping」だけでは障害を見抜けないのか
ネットワークの基礎をかじった者なら誰もが最初に覚えるのがpingコマンドだ。宛先IPアドレスを指定して死活監視を行う。しかし、デフォルトのpingが送信しているデータサイズがいかに「お飾り」であるかに気づいている人は意外と少ない。
多くのOS(Linuxなど)のデフォルト設定では、pingが送出するICMPエコーリクエストのデータペロードはわずか56バイト。IPヘッダー(20バイト)とICMPヘッダー(8バイト)を合わせても、合計たったの84バイトだ。
インターネットの標準的なイーサネットMTUは1500バイトである。84バイトのパケットなど、現在の巨大なネットワークパイプラインからすれば、砂漠の砂粒のようなものだ。こんな「お散歩パケット」で疎通確認をしたところで、実運用環境で発生している「数キロバイトのHTTPヘッダーやJSONボディを含むAPIリクエストの断片化失敗」を見抜けるはずがない。
ここに、インフラ運用における最大の落とし穴がある。
—
2. MTU超過とDFフラグ(Don’t Fragment)のメカニズム
ネットワーク機器や端末は、一度に送信できる最大のデータサイズであるMTUを持っている。通常のインターネット経路であれば1500バイト、AWSのVPC内や多くのクラウド環境でもデフォルトは1500バイト(あるいはジャンボフレームで9001バイトなど)に設定されている。
ここで問題になるのが IPヘッダーのフラグメントフィールド に存在する DF(Don’t Fragment:フラグメント禁止)フラグ だ。
パケットがMTUを超えるとき何が起きるか
1. DFフラグが立っていない場合:
ルーターの送信インターフェースのMTUを超えるパケットが来ると、ルーターは親切心からパケットを分割(フラグメンテーション)して下流へ送り出す。受信側でこれを再組立(リアセンブリ)するため、CPUに負荷がかかり、現代の高速ネットワークにおいてはボトルネックの元凶となる。そのため、現代のWeb APIやクラウド環境では、実質的にフラグメンテーションは嫌われ者だ。
2. DFフラグが立っている場合(現代の標準):
ルーターはパケットを分割することを禁止されている。もしルーターのMTUを超えるパケットが到着し、かつDFフラグが有効になっていれば、ルーターはそのパケットを容赦なく破棄(ドロップ)する。そして、送信元に対して「ICMP Destination Unreachable: Fragmentation Needed (Type 3, Code 4)」というエラーメッセージを送り返す。これが Path MTU Discovery (PMTUD) の根幹だ。
しかし、セキュリティ上の理由や不適切なファイアウォール(ICMPのブラックホール化)により、この「Fragmentation Needed」のICMPメッセージが送信元に届かないケースが後を絶たない。結果として、送信元はパケットが途中で消えていることすら気づかず、永遠に無応答を待ち続ける――これが「特定のデータ量以上になると通信が完全にフリーズする」という悪名高いブラックホール・シンドロームの正体だ。
—
3. 実践!CLIによるMTU・DFフラグ検証の作法
現場でこの挙動を暴くために、私たちはOS標準のpingコマンドに備わる強力なオプションを駆使する。Linux環境をベースに、その実戦的なコマンドを叩いてみよう。
Linux (iputils-ping) における実践コマンド
パケットサイズを指定しつつ、DFフラグを立ててパケットを送り出す。
# パケットサイズを1472バイト(IP+ICMPヘッダーの28バイトを加えると合計1500バイト)に指定
# -M do は「DFフラグを立てて、フラグメンテーションを絶対に行うな(必要ならドロップしろ)」という最強の指令
ping -s 1472 -M do 8.8.8.8
もし、あなたの環境から宛先までのパスMTUが1500バイトであれば、このコマンドは正常に応答する。
しかし、途中にPPPoE環境(MTU 1454バイト)や、VPNトンネル(IPsec/GREなどによるオーバーヘッドでMTUが小さくなっている環境)が挟まっており、パスMTUが1500未満になっている場合、次のような無慈悲なエラーが返ってくる。
PING 8.8.8.8 (8.8.8.8) 1472(1500) bytes of data.
From 192.168.1.1 icmp_seq=1 Frag needed and DF set (mtu = 1500)
# あるいは経路上のルーターから "Fragmentation needed" が返る
ここで重要なのは、「自分のマシンのインターフェースMTUが1500であっても、通信経路(Path)のどこかにそれより小さなMTUの区間があれば、そこでパケットは死ぬ」という現実だ。
macOS / FreeBSD の場合
OSによってコマンドのオプションが異なるのもインフラエンジニアの頭痛の種だ。macOSで同様の検証を行う場合は、以下のように指定する。
# -D は DFフラグを立てるオプション
# -s でペイロードサイズを指定(全パケットサイズではなくペイロードなので注意)
sudo ping -D -s 1472 8.8.8.8
—
4. アプリケーション層(Web API / HTTP)への影響とコードでの検証
ネットワーク層のMTU問題は、そのまま上位レイヤーのアプリケーション障害に直結する。特にJSONのPOSTリクエストや、画像・ファイルアップロードのような大容量ペイロードを扱うWeb API設計において致命的だ。
TCPの初期ハンドシェイク時には MSS (Maximum Segment Size) のネゴシエーションが行われるため、通常はTCPレイヤーで適切な大きさにセグメント化される。しかし、Path MTU Discoveryが途中のルーターのファイヤーウォール(ICMP遮断)によって阻害されている場合、TCPのウィンドウサイズやセグメントサイズがパスの実力値とミスマッチを起こし、TLSハンドシェイク完了後のデータ送信フェーズで突然コネクションが固まる(Zero Windowや再送タイムアウトの嵐)という現象が発生する。
この問題を切り分けるため、インフラエンジニアだけでなくバックエンド開発者も、自ら書くコードやスクリプトからネットワークの挙動を模擬・検証できなければならない。
Pythonによるリクエスト時の挙動検証スクリプト
Pythonのrequestsライブラリ等を使用してAPIを叩く際、背後でどのようなソケットオプションが働いているか、あるいは大きなペイロードを送った際にタイムアウトが発生するかを検証するスニペットを記す。
import requests
import sys
# テスト用のAPIエンドポイント
url = "https://api.example.com/v1/upload"
# 意図的に巨大なデータペイロードを作成(約2MBのJSON文字列)
# ネットワーク層のMTU問題だけでなく、アプリケーションのバッファサイズやタイムアウト検証にも利用する
large_payload = {
"data": "A" * (2 * 1024 * 1024)
}
try:
print(f"巨大なペイロード({sys.getsizeof(large_payload)} bytes)の送信テストを開始...")
# 接続タイムアウト(connect)を3秒、読込タイムアウト(read)を10秒に設定
# PMTUDの失敗によるブラックホール化では、大抵ここでReadTimeoutに落ちる
response = requests.post(url, json=large_payload, timeout=(3, 10))
print(f"レスポンス受信成功: Status Code {response.status_code}")
except requests.exceptions.Timeout:
print("[ERROR] タイムアウトが発生しました。")
print("-> 考察: パス上のMTU超過によるICMPドロップ(PMTUDブラックホール)または過大なペイロードが原因の可能性があります。")
print("-> 対策: pingコマンドで -M do を使ったMTUサイズ検証を実施してください。")
except requests.exceptions.RequestException as e:
print(f"[ERROR] その他の通信エラー: {e}")
curlによるデバッグの極意
現場でパパッとAPIの疎通とMTU関連の挙動を疑うときは、curlにverboseオプション(-v)を付与し、さらにトレース情報を引き出す。
# -v でTLSハンドシェイクやHTTPヘッダーのやり取りを詳細に出力
curl -v -X POST "https://api.example.com/v1/health" \
-H "Content-Type: application/json" \
-d '{"check": "MTU verification"}'
もし、Connected to api.example.com の表示が出た直後、> POST /v1/health HTTP/1.1 を送信したきりピタリと止まり、数秒後に curl: (56) Recv failure: Connection reset by peer や Operation timed out が返ってくる場合、それはレイヤー3/4の断片化・MTU問題の臭いがプンプンする。即座にpingによるパスMTU調査へ移行すべきシグナルだ。
—
5. シニアエンジニアからの実務Tips:障害シューティングのチェックリスト
最後に、現場であなたがMTU起因の障害に直面したとき、迷わず真犯人を突き止めるためのチェックリストを授けよう。
1. インフラの境界線を疑え:
社内LANからクラウド(AWS/GCP/Azure)への通信、あるいは拠点間のIPsec VPNトンネルを越える通信でこの障害は多発する。VPNのオーバーヘッド(カプセル化)により、通常の1500バイトのパケットが許容されなくなるケースが王道だ。
2. MSS Clampingを設定せよ:
ルーターやファイアウォールのレイヤーで、TCPのMSSを強制的に書き換える「MSS Clamping(例: mss 1360 などにクランプする)」が適切に設定されているか確認する。これだけで、ICMPが遮断されている環境でもTCPのフラグメント起因のトラブルの多くは消え去る。
3. クラウド側のセキュリティグループ / NACLを確認せよ:
AWSなどのセキュリティグループはステートレスではない(NACLはステートレス)ため、ICMPの「Fragmentation Needed」を誤ってセキュリティグループやインバウンド/アウトバウンドのルールでブロックしていないか?ここを塞いでいると、PMTUDは完全に機能を停止し、ブラックホールが完成する。
ネットワークは嘘をつかない。パケットの1ビット、フラグの1つひとつに、必ず「理由」がある。
「pingが通るからネットワークは大丈夫」という幻想を捨て、ペイロードのサイズを操り、DFフラグを立ててパケットの限界領域を暴く――この泥臭いアプローチこそが、障害を最速で鎮圧する唯一の武器となるのだ。
コメント