泥沼の夜を越えるための「Recv-Q/Send-Q」の深淵
深夜2時、監視アラートが鳴り響く。ダッシュボードは真っ赤に染まり、アプリケーション層からの「レスポンスが返ってこない」という悲鳴が届く。多くのエンジニアはまず top を叩き、次に iostat を確認するだろう。だが、ネットワークの深淵を覗き込むのならば、まず叩くべきは ss コマンドだ。
特に、その出力結果に含まれる Recv-Q と Send-Q。この二つの数字は、単なる統計ではない。これはカーネルのメモリ空間に滞留する「悲鳴の積層」であり、ネットワークスタックがどこで窒息しているかを雄弁に物語るシグナルである。
—
1. Recv-Q/Send-Q:パケットの「滞留」が告げる真実
まずは基本を整理しよう。ss -nt を叩いた時に表示されるこれらの値は、以下の意味を持つ。
Recv-Q: カーネルの受信バッファに滞留し、アプリケーションがまだread()していないバイト数。Send-Q: アプリケーションがwrite()したが、まだ相手からACKが返ってきておらず、再送待ちまたは送信待ちのバイト数。
ここが常にゼロに近い状態が「正常」だが、障害時はここが跳ね上がる。
Recv-Q が積もり続ける時:アプリの敗北
Recv-Q が恒常的に大きい場合、原因はシンプルだ。アプリケーションの処理能力が、ネットワークの到達速度に追いついていない。
TLSハンドシェイクが重いのか、あるいはバックエンドDBのクエリがロックを掴んでいるのか。Linuxカーネルは「パケットは受け取ったぞ、あとはアプリが処理しろ」とTCPウィンドウを制御して相手を待たせているが、限界を超えれば ZeroWindow を通知し、通信は事実上のフリーズを迎える。
Send-Q が積もり続ける時:ネットワークの限界
逆に Send-Q の増大は、相手先が受信を拒否しているか、回線が飽和していることを示す。特に、カーネルのTCP送信キューが溢れると、カーネルは送信待ちパケットを破棄するか、ウィンドウサイズを絞り込み、スループットは劇的に低下する。
—
2. 現場で使える「診断の作法」
単に値を眺めるだけでは不十分だ。以下のコマンドで「どのプロセスが、どれだけ詰まっているか」を構造的にあぶり出す。
# 接続状態とキューの滞留状況を監視する(Recv-Q/Send-Qを可視化)
watch -n 1 'ss -ntp | awk "NR==1 || \$2 > 0 || \$3 > 0"'
もし Recv-Q が異常に高いプロセスを見つけたら、strace を併用してシステムコールを追跡する。
# 特定PIDのreadコールを追跡し、処理のどこで詰まっているかを特定する
strace -p <PID> -e trace=read,recvfrom -f
—
3. パフォーマンスの境界線を押し広げるチューニング
もしボトルネックがアプリではなく「TCPスタックのデフォルト値」にあるなら、sysctlでテコ入れを行う必要がある。特に10Gbps以上の広帯域環境では、デフォルトのバッファサイズは「小さすぎる」ことが多い。
/etc/sysctl.conf に以下の設定を投入し、TCPのフロー制御を最適化する。
# TCP受信バッファの最小値、デフォルト値、最大値を拡張
# 16MB程度まで引き上げることで、高RTT環境でもスループットを維持する
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
# 送受信バッファの自動チューニングを有効化
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
# 輻輳制御アルゴリズムをBBRに変更(パケットロス率が高い回線で劇的な効果)
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
なぜ BBR なのか?
従来の CUBIC はパケットロスを「混雑」と見なすが、BBR はパケットの往復時間(RTT)と帯域幅を計測し、「実際のボトルネック」を推測する。高負荷なデータセンター内ネットワークでは、バッファ溢れによる偶発的なロスが発生しやすい。BBR を導入することで、この「バッファの海」を泳ぎ切る力が向上する。
—
4. 脆弱性とセキュリティの観点:TLSハンドシェイクの最適化
Recv-Q が増える要因の一つに、実は「TLSのハンドシェイクコスト」がある。特に ECDHE を多用する環境では、CPUの演算能力がボトルネックとなり、TCPコネクションを確立した後、データ受信までの時間が長引く。
- TLS 1.3の強制:
0-RTTを活用し、ハンドシェイクの往復回数を減らす。 - ALPNとヘッダー圧縮:
HTTP/2またはHTTP/3 (QUIC)を導入せよ。特にQUICはUDPベースであり、TCPのヘッド・オブ・ライン・ブロッキング(HOLB)を回避できる。TCPのRecv-Qが溢れるのを待つのではなく、ストリームごとに独立した制御が可能なアーキテクチャへの移行こそが、現代のインフラ設計における「最強の脆弱性対策」だ。
—
結論:ログの向こう側を見る
ネットワーク監視とは、数字の羅列を眺めることではない。カーネルとアプリケーションが、メモリという限られたリソースを巡ってどのような「交渉」を行っているかを読み解くことだ。
ss コマンドで Recv-Q が跳ねた瞬間、それは単なるエラーではなく、システム全体が悲鳴を上げているSOSだ。そのSOSを、設定値の変更やアプリの非同期処理化で静かに鎮めてやるのが、我々エンジニアの腕の見せ所だ。
泥臭いトラブルシューティングを厭わず、プロトコルの挙動を愛し続けよう。パケットは嘘をつかない。ただ、我々がそれを読み解くための「教養」を求めているだけなのだから。
コメント