現場で泣かないためのTCPソケット診断:netstatとssで「見えない通信」を可視化する
深夜3時、アラートが鳴り響く。監視ダッシュボードには「APIレスポンスタイムの急増」と「503 Service Unavailable」。負荷試験中やピーク時の障害対応で、多くのエンジニアがまず直面するのが「コネクションの枯渇」だ。
「負荷は高くないはずなのに、なぜか繋がらない」。そんな時、教科書的なマニュアルを読んでいる暇はない。君たちがまず叩くべきは、TCPの死活状態を教えてくれるnetstat、あるいはその後継であるssコマンドだ。今日は、ネットワークの深淵を覗くための「生存戦略」を授けよう。
—
1. TCPの状態遷移を「現場の肌感覚」で理解する
TCPは単なる通信のルールではなく、握手から別れまでを律儀に守る「紳士的なプロトコル」だ。この状態遷移を理解していないと、障害の真因には辿り着けない。
LISTEN: 「いつでも来い」とポートを開けて待機している状態。ESTABLISHED: 互いに握手を交わし、パケットを投げ合っている「戦場」そのもの。CLOSE_WAIT: ここが最重要だ。 クライアントから切断通知(FIN)を受け取ったが、サーバー側でclose()処理が走っていない状態。「まだ送るデータがあるかも」とOSが気を利かせて保持しているが、放置すればリソースリークの温床になる。TIME_WAIT: 通信終了後、迷子のパケットを拾うためにあえて残している「余韻」の時間。これが多すぎると、新規コネクションを張るためのソースポートが枯渇し、接続エラーが頻発する。
—
2. 現場の武器:ssコマンドを使いこなす
最近のLinux環境では、netstatは非推奨になりつつある。カーネル内部の情報を直接引き出すssコマンドこそが、トラブルシューティングの正当な後継者だ。
アクティブなTCP接続を数える
まずは、今何が起きているかを一撃で把握する。
# 全てのTCP接続をリストアップし、状態別にカウントする
ss -nt | awk '{print $1}' | sort | uniq -c
ここでTIME_WAITが数万単位で積み上がっているなら、OSのチューニング、あるいはアプリケーション側のコネクション管理を疑うべきだ。
悩めるCLOSE_WAITを特定する
もしAPIサーバーでCLOSE_WAITが大量発生しているなら、それはアプリケーションコードがソケットを正しくクローズしていないサインだ。
# CLOSE_WAIT状態の通信をプロセスID(PID)付きで表示する
ss -npt state close-wait
このコマンドでPIDを特定し、ps -fp <PID>でどのプロセスが「握りっぱなし」にしているかを突き止める。これが現場の定石だ。
—
3. コードレベルでの「コネクション管理」を再考する
通信が切れない、あるいは接続数が増えすぎる問題の多くは、クライアント側の実装にある。例えば、Pythonのrequestsモジュールを使う際、セッションを使い回さずに毎回コネクションを張っていないだろうか?
悪い例:毎回コネクションを閉じて開く(ポート枯渇の原因)
import requests
# ループのたびにTCPハンドシェイクが発生し、TIME_WAITが量産される
for _ in range(1000):
response = requests.get("http://api.example.com/data")
良い例:SessionオブジェクトでKeep-Aliveを活用する
import requests
# Sessionを使うことでTCP接続を再利用(Keep-Alive)する
session = requests.Session()
for _ in range(1000):
response = session.get("http://api.example.com/data")
このように、コネクションを「使い捨てる」のではなく「再利用する」設計にするだけで、TIME_WAIT問題の9割は解決できる。
—
4. インフラ側で打てる最後の防波堤
アプリ側の改修が即座にできない場合、あるいはOSレベルでのチューニングが必要な場合は、カーネルパラメータを触る。sysctlの設定ファイル(/etc/sysctl.conf)を覗いてみよう。
# TIME_WAIT状態のソケットを高速にリサイクルする(推奨)
net.ipv4.tcp_tw_reuse = 1
# ローカルポートの範囲を広げ、枯渇を防ぐ
net.ipv4.ip_local_port_range = 1024 65535
設定を反映した後は、必ず sysctl -p を忘れずに。
—
最後に:ネットワークは「生き物」である
障害対応の現場で最も恐ろしいのは、「何が起きているか分からない」状態だ。今日紹介したコマンドは、その暗闇を照らす松明に過ぎない。
通信が途絶えたとき、まずはss -ntでコネクションの偏りを見よ。次に、どのプロセスがその通信を握っているかを確認せよ。そして最後に、アプリケーションが適切にclose()を呼んでいるか、あるいはKeep-Aliveを有効にしているかを確認する。
ネットワークは決して嘘をつかない。パケットの挙動を追うことは、システムの魂を理解することと同義だ。さあ、次は君のターミナルで、この「見えない通信」を可視化してみせてくれ。現場からは以上だ。
コメント