深夜のデータセンター、冷気混じりのサーバーラックの間で、何度「パケットの断末魔」を聞いてきただろうか。
「APIのレスポンスが返ってこない」「特定のサブネットにだけ通信が届かない」……。そんな絶望的な報告が飛び込んできたとき、我々シニアエンジニアが真っ先に叩くコマンドの一つが netstat だ。
最近は ip route や ss コマンドに取って代わられつつあるが、POSIX準拠のシステムであればどこにでも居てくれる、古き良き相棒だ。今回は、Web API開発者やインフラ担当者が「現場で生き抜く」ために必須となる、netstat を使ったルーティングとインターフェース統計の深掘り方法を伝授しよう。
—
1. ルーティングテーブルは「パケットの羅針盤」である
パケットがホストから旅立つとき、最初に見るのがカーネル内のルーティングテーブルだ。ここが狂っていれば、どんなに豪華なAPIを実装しても、パケットは虚空へと消えていく。
netstat -rn で現実を直視する
まずは、現在のルーティング状況を確認する基本の型だ。-r (routing) と -n (numeric:名前解決をせず数字で表示) を組み合わせるのが鉄則だ。
# ルーティングテーブルを表示する。-nを付けないとDNS逆引きで表示が遅れることがある。
$ netstat -rn
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
0.0.0.0 192.168.1.1 0.0.0.0 UG 0 0 0 eth0
10.0.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth1
192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
ここで注目すべきは Flags カラムだ。ここにはパケットの運命が記されている。
- U (Up): ルートが有効である。
- G (Gateway): ゲートウェイ(ルーター)を経由することを示す。
0.0.0.0の宛先(デフォルトゲートウェイ)には必ずこのフラグが立つ。 - H (Host): 特定の1ホストへのルート。
現場のTips:
もしAPIの接続先が 10.0.0.5 なのに、ルーティングテーブルに 10.0.0.0/24 のエントリがなく、デフォルトゲートウェイ(0.0.0.0)に吸い込まれて外部ネットワークへ出ていこうとしていたら? そこで通信は遮断される。ルーティングの不整合は、コードを書く前の「土俵」の問題なのだ。
—
2. インターフェース統計から「ネットワークの悲鳴」を聴く
「通信は繋がっているが、なぜか時々遅い、パケットが落ちる」という微熱のような不具合。これを見抜くには netstat -i (interface) が不可欠だ。
# 全インターフェースの統計情報を確認
$ netstat -i
Kernel Interface table
Iface MTU RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg
eth0 1500 124502 0 0 0 105670 0 0 0 BMRU
lo 65536 2405 0 0 0 2405 0 0 0 LRU
統計値が語る真実
- RX-ERR / TX-ERR: 受信・送信時のエラー数。ここが増えているなら、物理レイヤー(ケーブル不良、SFPモジュールの劣化)か、ドライバの不整合を疑え。
- RX-DRP (Drop): カーネルの受信バッファが溢れたか、パケットフィルタリングで捨てられた数だ。APIへのバーストアクセスにシステムが耐えきれていない兆候かもしれない。
Web APIのパフォーマンスが出ないとき、アプリケーションのプロファイリングを始める前に、この RX-DRP が増えていないかチェックしてほしい。OSレベルでパケットを捌ききれていないなら、いくらPythonやGoのコードを最適化しても無意味だからだ。
—
3. 実務でのデバッグ・ワークフロー
ここからは、API開発者が遭遇しがちな「特定のマイクロサービスと通信できない」というケースを想定したデバッグ手順を示そう。
手順1: 通信経路の疎通確認
まずは curl での挙動を確認し、その後 netstat で足元を固める。
# タイムアウトを短く設定して接続確認
$ curl -v --connect-timeout 5 https://api.internal.service/v1/health
# 接続できない場合、そもそもどのインターフェースから出ようとしているか確認
$ netstat -rn
手順2: 宛先ネットワークへのルートが存在するか?
例えば、宛先が 172.16.50.10 なら、それを含むセグメントが Iface(例えば eth1)に紐付いているかを見る。もし無ければ、静的ルートの追加が必要になる。
# Linuxでの静的ルート追加例(一時的)
# 172.16.50.0/24 宛の通信は 192.168.1.254 を通れ、という指示
$ sudo ip route add 172.16.50.0/24 via 192.168.1.254 dev eth0
—
4. Pythonによるネットワーク監視の自動化
インフラ運用においては、手動でコマンドを叩くのは最初の一歩に過ぎない。重要なのは「異常の予兆」を検知することだ。psutil ライブラリを使えば、netstat -i 相当の情報をプログラムから容易に取得できる。
import psutil
import time
def monitor_interfaces():
"""
インターフェースの統計情報を監視し、エラー率を算出する
"""
# 初回取得
old_stats = psutil.net_io_counters(pernic=True)
while True:
time.sleep(5)
# 5秒後の統計取得
new_stats = psutil.net_io_counters(pernic=True)
for iface, stats in new_stats.items():
drop_diff = stats.dropin - old_stats[iface].dropin
err_diff = stats.errin - old_stats[iface].errin
if drop_diff > 0 or err_diff > 0:
print(f"[ALERT] Interface {iface}: Errors={err_diff}, Drops={drop_diff}")
# ここでSlack通知やログ出力を行うのが現場流
else:
print(f"[INFO] Interface {iface}: Healthy")
old_stats = new_stats
if __name__ == "__main__":
monitor_interfaces()
—
結びに代えて:パケットの気持ちを理解する
RFC 791(IP)や RFC 793(TCP)を読み込むのも良い。しかし、トラブルの現場で最後にモノを言うのは、こうした泥臭いコマンドが吐き出す「生の数字」との対話だ。
netstat -r が示すのは、ホストが世界をどう見ているかという「地図」であり、netstat -i が示すのは、その地図を歩く足元の「健康状態」だ。
Web APIの設計者であっても、パケットが物理的なNICを通り、カーネルのルーティング判断を経て、インターネットの荒波へと消えていく一連のシーケンスを想像してほしい。その想像力こそが、堅牢なシステムを構築する最強の武器になるのだから。
次に画面が「Connection Timeout」を吐き出したとき、君が冷静に netstat -rn を叩けることを願っている。
コメント