「え、ルートが変わるの?」ECMP環境で迷子にならないためのtraceroute攻略術
ネットワークエンジニアの皆さん、こんにちは。現場で叩き上げられてきたNOCの「古参」として、今日は皆さんが一度は頭を抱えるであろう「tracerouteの罠」についてお話ししようと思います。
ネットワークを監視していると、たまにこんな現象に出くわします。「さっきまで通っていた経路と、今通っている経路が違うぞ?」と。実はこれ、現代のデータセンターでは日常茶飯事。今回は、この迷路のようなネットワークを正確に解き明かすための「TCP traceroute」という技術を、噛み砕いて解説していきますね。
—
そもそも、なぜ経路が変わるのか?(ECMPの正体)
データセンターの巨大なネットワークでは、通信の負荷を分散させるために、一台のルーターから次のルーターへ向かう道が何本も用意されています。これを「ECMP(等コストマルチパス)」と呼びます。
身近な例で例えてみましょう。
あなたが東京から大阪へ荷物を送るとします。郵便局のトラックが「Aルート」「Bルート」「Cルート」の3本を同時に使って荷物を運ぶようなものです。
- ある荷物はAルートへ
- ある荷物はBルートへ
これ、効率は最高ですが、調査する側からするとたまったもんじゃありません。「さっきの荷物はAを通ったけど、今の荷物はBを通っている」ということが起きるからです。
従来のtracerouteが抱える「嘘」
私たちが普段使う traceroute(あるいはWindowsの tracert)は、基本的には「UDP」や「ICMP」という種類のパケットを送り出します。しかし、これらは「宛先IPアドレス」だけを見て経路を決めることが多く、ECMPの環境下では「パケットごとにバラバラのルートを通ってしまう」という性質があります。
結果として、出力される経路情報が「実際には存在しない、継ぎはぎだらけのルート」になってしまうことも珍しくありません。現場で「この経路、おかしいぞ?」と混乱するエンジニアの多くは、この罠にハマっています。
救世主「TCP traceroute」の登場
ここで登場するのが、TCPベースのtracerouteです。
なぜTCPが良いのか? それは「ポート番号」という情報を固定できるからです。
ECMPのルーターは、パケットの「宛先IP」だけでなく「ポート番号」も見て、どのルートを通すかを決めています。つまり、「宛先IP」と「ポート番号」を固定して連続で送り続ければ、ルーターは『お、これは同じ荷物だな。じゃあ同じルートを通そう』と判断してくれるんです。
これが、今回紹介する「Paris traceroute」などの考え方の根幹です。
—
実践!TCP tracerouteを使ってみよう
Linux環境であれば、tcptraceroute というツールが非常に優秀です。もし入っていなければ sudo apt install tcptraceroute などで簡単に入りますよ。
1. 基本的な使い方
まずは、特定のポート(例えばWebサーバーなら 80 や 443)を指定して実行してみましょう。
# 宛先サーバーの443番ポートに向けてTCPパケットを投げる
# -n: DNS逆引きをしない(結果を早く出すため)
# -q 1: 各ホップで送るパケット数を1にする(負荷軽減)
sudo tcptraceroute -n -q 1 192.168.1.100 443
2. なぜこれで正確になるのか?
このコマンドは、指定した 443 ポートを使って「SYNパケット(通信開始の合図)」を送り続けます。ルーターたちは、この「IP + ポート」の組み合わせをひとつの「フロー(荷物の流れ)」として認識するため、追跡中の経路がブレにくくなるのです。
—
現場で役立つ運用のコツ
新米エンジニアの皆さんが現場でトラブル対応をする際、以下のポイントを意識するだけでグッと信頼されるようになります。
1. ポート番号の選定:
目的のサーバーが動いているポート(80, 443, 22 など)を使いましょう。そもそも閉じているポートを指定しても、途中のファイアウォールで弾かれてしまい、正確な調査ができません。
2. 連続して実行してみる:
それでも経路がブレる場合は、途中の機器で何らかの動的な負荷分散が行われています。「同じ条件(ポート固定)」で何度か実行し、結果が一致するかどうかを確認するのがプロのやり方です。
3. JSON出力の活用:
最近の運用監視ツールは traceroute の結果をログとして取り込むことが多いです。スクリプトを書く際は、解析しやすい形式で保存する癖をつけておきましょう。
# Pythonで簡易的に経路監視をする場合のイメージ(概念コード)
import subprocess
target = "192.168.1.100"
port = 443
# コマンドを実行して結果をキャプチャする
result = subprocess.run(
["tcptraceroute", "-n", "-q", "1", target, str(port)],
capture_output=True, text=True
)
# ログファイルに書き出す(後で傾向分析するため)
with open("network_path_log.txt", "a") as f:
f.write(f"--- {target}:{port} ---\n{result.stdout}\n")
—
最後に:ネットワークは「生き物」です
教科書には「正しいルート」が一本だけ描かれていますが、現実のデータセンターのネットワークは、常に膨大なトラフィックが流れる「生き物」です。
traceroute はあくまで「今、そのパケットが通った道」を見ているに過ぎません。今回お話しした「ポート固定」による追跡は、その生き物の挙動を正確に理解するための、私たちエンジニアの「聴診器」のようなものです。
ぜひ皆さんの環境でも、traceroute をただ打つだけでなく、「どのポートを指定すれば、この通信の本当の姿が見えるかな?」と一歩立ち止まって考えてみてください。その小さな思考の積み重ねが、いつか皆さんのトラブル対応能力を圧倒的に引き上げてくれるはずです。
それでは、また現場でお会いしましょう!
コメント