現場の「見えない断絶」を暴く:ssコマンドでTCPタイマーを視覚化する技術
夜中の3時、アラートの通知音で叩き起こされ、ダッシュボードの真っ赤なグラフを眺める。「APIのレイテンシが急増し、その後パケットロスが発生している」。そんな修羅場をくぐり抜けてきた諸君ならわかるはずだ。ネットワークの障害は、往々にして「ログには何も残らない」場所で起きる。
アプリケーション層で 504 Gateway Timeout を連発しているとき、我々NOCのエンジニアが真っ先に手を伸ばすのは、tcpdump や wireshark の巨大なパケットキャプチャではない。まずは、カーネルの直近の記憶を覗き込むことだ。
今日は、現代のインフラ運用における最強の武器の一つ、ss コマンドを用いた「TCPタイマー」の解読法について解説しよう。
—
なぜ ss でタイマーを見るのか
netstat がレガシーな遺物となりつつある今、後継の ss コマンドがなぜ優秀なのか。それは単に処理が速いからではない。カーネル内のソケット情報を、より詳細かつ低負荷に引き出せるからだ。
特に -o (option) オプションは、TCPの通信が今どんな「焦燥感」を抱えているかを教えてくれる。Keep-Aliveの残り時間や、再送(Retransmit)の試行回数。これらは、パケットがネットワークのどこかで「迷子」になっているか、あるいは対向サーバーが「沈黙」しているかを見極めるための羅列だ。
基本コマンドと出力の見方
まずは、手元のLinuxサーバーで以下のコマンドを叩いてみてほしい。
# -t: TCPソケットを表示
# -a: すべてのソケットを表示
# -n: 数値形式(名前解決しない)
# -o: タイマー情報を表示
ss -tan -o
出力の末尾に、timer:(...) という奇妙な文字列が見えるはずだ。これが今回扱う核心部分である。
—
タイマーの正体:RFCの向こう側
出力される値は、主に以下の3つのタイマーを指している。
1. on (Retransmit timer): パケットを送信したがACKが返ってこない状態。ss は「あと何ミリ秒で再送を開始するか」を表示する。ここが頻繁に動いているなら、物理回線の輻輳か、パケットドロップを疑え。
2. keepalive (Keep-Alive timer): アイドル状態の接続を維持するためのタイマー。HTTP/1.1の Connection: keep-alive とは別に、OSレベルでコネクションが生きてるかを確認するパルスだ。
3. timewait (Time-Wait timer): 接続終了後の「余韻」期間。これが溜まりすぎると、新しい接続を受け入れられなくなる(いわゆる「ポート枯渇」)。
—
現場での活用ケース:再送地獄を追跡する
APIサーバーが突如として「応答なし」になる現象を追うとき、我々はまず再送回数を確認する。
もし ss で以下のような出力が見えたら注意が必要だ。
ESTAB 0 120 10.0.0.1:443 192.168.1.50:56782 timer:(on,200ms,0)
この timer:(on, 200ms, 0) の意味は、「200ms後に最初の再送を試みる(on)、現在の試行回数は0」ということだ。もし、この数値が 1.2s、2.4s と指数関数的に増えていくなら、ネットワークのどこかでブラックホールが発生している。
Pythonによる検証用コード
実際に、わざとパケットを捨てて ss で確認するための簡単なツールを書いてみた。
import socket
# 特定のサーバーへ接続し、敢えて何も送らずに放置してKeep-Aliveを観察する
def check_socket_state():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("127.0.0.1", 8080))
# Keep-Aliveを有効にする
s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
# この状態でCLIから ss -tan -o を実行すると、
# keepaliveタイマーがカウントダウンされているのが見えるはずだ
input("何かキーを押すと閉じます...")
s.close()
if __name__ == "__main__":
check_socket_state()
—
運用上のTips:なぜ「沈黙」は起きるのか
実務において、このタイマー情報を駆使して解決した事例を一つ挙げよう。
ある日、Web APIの通信が特定のクライアントだけ異常に遅いという報告があった。ログを追うと、クライアントからのリクエストは届いているが、レスポンスが「再送(Retransmit)」を繰り返している。
ss で確認したところ、timer:(on, ...) の再送回数が異常に伸びていた。原因を辿ると、途中のロードバランサー(L4スイッチ)のMTU設定がミスっており、大きなパケットだけがドロップしていたのだ。curl でサイズを指定して通信テストを繰り返したことで、問題のパケットサイズを特定できた。
現場で役立つコマンドラインTips
トラブルシューティング時は、以下のように watch を組み合わせて「変化」を観察するのが鉄則だ。
# 2秒ごとにソケット状態を監視し、再送タイマーの変化をリアルタイムで追う
watch -n 2 "ss -tan -o | grep -v 'ESTAB'"
—
最後に:ネットワークを「感じる」こと
ネットワークエンジニアの仕事は、画面上の数字を現実の物理挙動に翻訳することだ。ss のタイマー情報は、単なるカーネルの変数ではない。それは、遠く離れたサーバーが「まだ生きていますか?」と不安げに問いかけている鼓動そのものだ。
教科書的な RFC793(TCP仕様)を暗記するだけでは足りない。現場でトラブルが起きたとき、そのタイマーの数字が「急激に増えているのか」、それとも「微動だにしないのか」を読み解く感性を磨いてほしい。
次に障害対応の現場に立ったとき、まずは ss -tan -o を叩いてみてほしい。そこには、君の知らないネットワークの真実が刻まれているはずだ。健闘を祈る。
コメント