【実務・中級編】 ジャンボフレーム導入時のMTU不一致によるパケットフラグメンテーションと性能劣化 – インフラ・物理&L2/L3ネットワーク基礎実践ガイド

ネットワークの「見えない断崖」:MTU不一致が引き起こすパケットの悲劇

ネットワークエンジニアとして現場を渡り歩いていると、幾度となく「なぜか特定の通信だけが異常に遅い」「大きなファイルを転送すると決まって固まる」という怪奇現象に遭遇します。アプリ開発者がどれほどコードを最適化しても、DB管理者がクエリをチューニングしても解決しない。その原因の多くは、下位レイヤー、具体的にはMTU(Maximum Transmission Unit)の不一致という「見えない断崖」にあります。

今日は、ジャンボフレームを導入する際、あるいはクラウド環境へ移行する際に多くのエンジニアが陥る「MTU不一致によるパケット断片化」の深淵を覗いていきましょう。

—

1. なぜ「1500」という数字が呪縛となるのか

イーサネットの標準的なMTUは1500バイトです。これは歴史的な経緯やコスト、技術的な制約が積み重なった結果ですが、現代のデータセンターや高速ネットワークでは、オーバーヘッドを減らしてスループットを稼ぐために「ジャンボフレーム(9000バイト等)」を有効にすることがあります。

ここで問題になるのは、エンドツーエンドの「経路のどこか一箇所でもMTUが小さいと、その先の機器がパケットを処理しきれない」という単純かつ残酷な事実です。

経路上の断片化(Fragmentation)の結末

送信側が9000バイトのパケットを送り出した際、経路上のルーターが「おっと、次のリンクはMTUが1500しかないぞ」と判断すると、ルーターはパケットを分割(フラグメンテーション)せざるを得ません。

  • ルーターの負荷増大: 全てのパケットをCPUで分解・再構築するのは、ルーターにとって重い処理です。
  • ドロップの誘発: もしパケットにDF(Don’t Fragment)ビットが立っていれば、ルーターはそのパケットを即座に破棄し、送信側にICMP Type 3 Code 4(Destination Unreachable / Fragmentation Needed)を返します。
  • 「パスMTUブラックホール」の発生: セキュリティポリシーでICMPを全遮断しているネットワークでは、このエラー通知が届かず、通信が永遠にタイムアウトし続ける「ブラックホール」状態に陥ります。

—

2. 現場で使えるデバッグの極意:pingによるMTU調査

トラブルシューティングの第一歩は、どのサイズまで通信が通るかを物理的に確認することです。pingコマンドのオプションを使い、ペイロードサイズを指定してパケットを送り込みましょう。

# macOS/Linuxの場合:-DはDFビットの設定、-sはペイロードサイズ
# 1472(ペイロード) + 20(IPヘッダー) + 8(ICMPヘッダー) = 1500バイト
ping -D -s 1472 192.168.1.1

# もしジャンボフレーム(9000)をテストするなら
# 8972 + 20 + 8 = 9000バイト
ping -D -s 8972 192.168.1.1

もしpingが通らない場合、その経路のどこかにMTUのボトルネックが存在します。

—

3. 実装レベルでの確認:curlとTCP MSS

Web APIを開発していると、curlを使ってレスポンスを確認することが多いはずです。ここで、「ヘッダーは取れるのにボディが受信できない」という現象はMTU問題の典型です。

# -v オプションで通信の詳細を表示
# 途中で止まる場合は、MTUの不一致を疑う
curl -v https://api.example.com/large-data

また、TCP通信にはMSS(Maximum Segment Size)という概念があります。これはMTUからIPヘッダーとTCPヘッダーの分を引いた値です(通常1460バイト)。通信開始時の3ウェイ・ハンドシェイクで、双方のNICがこのMSSをネゴシエーションしますが、途中のルーターが勝手にパケットを弄ると、この整合性が崩れます。

PythonによるMTU確認(Scapyを用いたパケット解析)

より高度な調査が必要な場合、Scapyを使ってパケットのフラグを直接確認することもあります。

from scapy.all import IP, ICMP, sr1

# DFビット(flags=2)を立てて、特定のサイズのパケットを送る
pkt = IP(dst="192.168.1.1", flags=2)/ICMP()/"X"*1472
reply = sr1(pkt, timeout=2)

if reply:
    print("通信成功: MTUは1500以上です")
else:
    print("通信失敗: パスMTUが小さいか、ICMPが遮断されています")

—

4. インフラエンジニアへの処方箋:設定上の注意点

もしあなたがクラウドのVPCやオンプレミスのスイッチを設定しているのであれば、以下の「鉄則」を守ってください。

1. 一貫性の保持: 全経路(ホストNIC、物理スイッチ、ルーター、VPNトンネル)のMTUを必ず合わせる。
2. クラウド環境の特殊性: AWSやGCPなどのクラウド環境では、インスタンスのMTUが9001バイト(ジャンボフレーム対応)であっても、通信先のロードバランサーや外部ネットワークが1500バイト固定であることが多々あります。
3. MSSクランプの設定: どうしてもMTUを統一できない場合、ルーター側でTCP MSS Clampingを有効にしてください。これは、TCPのSYNパケットを監視し、MSS値を強制的に書き換えることで、フラグメンテーションを防ぐ救済措置です。

Cisco系機器でのMSSクランプ例:

interface GigabitEthernet0/1
 ip tcp adjust-mss 1460  # TCP通信に対してMSSを1460に制限

—

最後に:ネットワークは「正直」である

MTU問題は、ネットワークが非常に正直であることを教えてくれます。設定の不整合は、たとえわずかな差であっても、必ずパケットの破棄やレイテンシの増大として現れます。

「なぜか遅い」という直感を感じたら、まずはMTUを疑ってください。コマンド一つ、設定一行の修正で、今まで悩んでいたパフォーマンスの問題が霧のように消え去る瞬間こそ、この仕事の醍醐味です。

皆さんのインフラが、今日も高いスループットを維持し、パケットロスなく駆け巡ることを願っています。それでは、また現場でお会いしましょう。

コメント

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