隠れた遅延:TCP再送(Retransmissions)を理解する
スペック上、Linuxサーバーの状態は完璧に見えるかもしれません。CPU使用率は5%でアイドル状態、空きメモリも数ギガバイトあるのに、アプリケーションの動作が遅く感じることがあります。通常は20ミリ秒で終わるリクエストが、突然200ミリ秒や2秒に跳ね上がります。データベースやコードに問題がない場合、ボトルネックはネットワークスタック内のTCP再送(TCP Retransmissions)に隠れている可能性が高いです。
TCPは信頼性を重視して設計されています。送信側がパケットを送信すると、確認応答(ACK)を待ちます。再送タイムアウト(RTO)までにACKが届かない場合、送信側はパケットが消失したと判断して再送を試みます。これによりデータ損失は防げますが、パフォーマンスは著しく低下します。10Gbpsの回線であっても、わずか1%の再送が発生するだけで、実効スループットが50%以上低下することもあります。
私は、ネットワークスイッチのポート故障やMTUの不一致が原因で、高トラフィックなクラスターの動作が極端に遅くなるのを何度も見てきました。データベースクエリの書き直しに数日を費やした挙句、実はカーネルパラメータを1行修正するだけで解決した、というケースも少なくありません。
診断ツールの準備
パケットがどこで消失しているかを突き止めるには、いくつかの主要なユーティリティが必要です。その多くはすでにシステムに組み込まれていますが、一部はインストールが必要な場合があります。
1. iproute2 (ss および nstat)
ssとnstatツールはiproute2パッケージに含まれています。これはUbuntu、CentOS、Debian、Fedoraなどで標準的にインストールされています。ip addrコマンドが実行できる環境であれば、すでにこれらを利用可能です。
2. Wireshark および TShark
Wiresharkはデスクトップでの分析に最適ですが、リモートサーバー上ではコマンドライン版のtsharkを使用します。パッケージマネージャーを使ってインストールしてください。
# Ubuntu / Debian の場合
sudo apt update && sudo apt install tshark -y
# RHEL / CentOS / AlmaLinux の場合
sudo yum install wireshark-cli -y
nstat と ss で問題を特定する
いきなり膨大なパケットキャプチャを開始してはいけません。まずはカーネル内部のカウンターを確認し、問題の規模を把握しましょう。
nstat によるグローバル統計の確認
nstatコマンドはカーネルから直接メトリクスを取得します。最後に起動してからこれまでに再送されたセグメント数を確認するには、以下のコマンドを実行します。
nstat -az TcpRetransSegs
健全なネットワークでは、この数値は低いはずです。理想的には全セグメントの0.05%未満です。ベンチマーク実行中の現在の再送率を確認するには、1秒ごとに更新される以下のコマンドを使用します。
nstat -n 1 1
ss による個別のソケット調査
ss(socket statistics)ツールは、netstatに代わる現代的なツールです。非常に高速で、TCP接続の内部状態を表示できます。-iフラグを使用して詳細を確認しましょう。
ss -ti
出力結果のretransフィールドに注目してください。以下は問題のある接続の例です。
ESTAB 0 0 192.168.1.10:443 1.2.3.4:5678
cubic rto:204 rtt:0.187/0.037 mss:1448 cwnd:10 bytes_retrans:4500 retrans:0/1
retrans:0/1において、最初の数字は現在未確認の再送数を示し、2番目の数字はそのセッション中の合計再送数を示します。bytes_retransが数メガバイトに達している場合、そこがボトルネックです。
TShark による根本原因の分析
再送が発生していることがわかったら、失敗の「形」を確認する必要があります。サーバーが送信に失敗しているのか、それともクライアントが確認応答(ACK)を返せていないのかを調べます。
トレースのキャプチャ
アクティブなインターフェース(eth0など)のトラフィックを記録し、ファイルに保存します。ディスクを圧迫しないよう、キャプチャは短時間にとどめてください。
sudo tshark -i eth0 -f "tcp" -w trace.pcap
エラーのフィルタリング
問題のあるパケットだけを抽出するフィルタを使用してファイルを分析します。
tshark -r trace.pcap -Y "tcp.analysis.retransmission"
もし「Previous segment not captured」の後に再送が続くパターンが見られる場合、ロードバランサーやファイアウォールなどの上位デバイスが、サーバーに届く前にパケットをドロップしている可能性があります。
一般的なボトルネックに対する実証済みの解決策
問題を特定したら、状況に応じて以下の修正を適用してください。
1. 「ブラックホール」MTU の修正
小さなpingは通るのに、大きなファイル転送が99%で止まってしまう場合、MTUの不一致(MTU mismatch)が疑われます。これは、サーバーが1500バイトのパケットを送信しようとしているのに、経路上のVPNやトンネルが1400バイトまでしか処理できない場合に発生します。パケットは通知なく破棄(サイレントドロップ)されます。
テスト方法: パケットの断片化を禁止して、大きなパケットを送信してみます。
ping -M do -s 1472 8.8.8.8
これが失敗し、通常のpingが通る場合は、MTUを1400に下げてみてください。
sudo ip link set dev eth0 mtu 1400
2. カーネルバッファのボトルネックを解消する
nstatでTcpExtTCPBacklogDropが表示される場合、アプリケーションがカーネルのキューからデータを引き出す速度が追いついていないことを意味します。バッファがいっぱいになり、カーネルが新しいパケットを破棄し始めています。
/etc/sysctl.confのバックログ制限を増やして、アプリケーションに余裕を持たせます。
net.core.netdev_max_backlog = 5000
net.ipv4.tcp_max_syn_backlog = 4096
sudo sysctl -pを実行して設定を適用します。
3. BBR 輻輳制御への切り替え
デフォルトのcubicアルゴリズムは、長距離回線や混雑した回線でのパケット損失にうまく対応できません。GoogleのBBR(Bottleneck Bandwidth and Round-trip propagation time)はよりスマートです。軽微なパケット損失は無視し、実際のスループットに焦点を当てます。
以下のコマンドで有効にします。
sudo sysctl -w net.core.default_qdisc=fq
sudo sysctl -w net.ipv4.tcp_congestion_control=bbr
まとめチェックリスト
ネットワークが遅いと感じたら、以下のワークフローを試してください。
- nstat を実行し、グローバルの再送カウンターが増えていないか確認する。
- ss -ti を使用して、特定のIPアドレスとの通信で問題が発生していないか特定する。
- tshark でトレースをキャプチャし、パケットが順不同で届いていないか確認する。
- 大容量データ転送中に接続が切れる場合は、MTU サイズを確認する。
- 高レイテンシな地域間トラフィックを扱う場合は、BBR を有効にする。

