パフォーマンス低下のトラブルシューティング: 'netstat' と 'ss' の効果的な使い方

Linuxネットワーキングツール `netstat` と `ss` をマスターして、効率的なパフォーマンストラブルシューティングを実現しましょう。このガイドでは、レガシーな `netstat` と最新で高速な `ss` ユーティリティを比較し、実践的なコマンド例を提供します。接続状態による結果のフィルタリング、リッスン中のサービスの特定、Netlinkソケット統計を使用したネットワークボトルネックの迅速な診断方法を学びます。

パフォーマンス低下のトラブルシューティング: 'netstat' と 'ss' の効果的な使い方

Linuxサービスが遅いと感じたとき、ソケットテーブルは「アプリが過負荷」なのか「ネットワーク経路が乱れている」のかを切り分ける最も迅速な手段の一つです。新しい接続を受け入れられないWebサーバー、データベースセッションの開始で詰まっているワーカー、中途半端なTCPハンドシェイクが山積みのホストは、すべて待っている側から見れば漠然とした遅さにしか見えません。

netstatss は、より狭い質問に答えるのに役立ちます。このマシン上に現在どのようなネットワークソケットが存在するか、それらはどの状態にあるか、そしてどのプロセスが所有しているか、です。netstat は古いシステムや古いランブックでは今でも有用です。ss は、現代のLinuxで私が最初に手に取るツールです。なぜなら、ビジーなホスト上でより高速で、組み込みのフィルタリング機能が優れているからです。

なぜネットワークソケットを監視するのか?

ネットワークのレイテンシや応答の鈍さは、CPUやメモリの枯渇よりも、接続の問題に関連していることがよくあります。ソケットの監視は、管理者が以下のような重要な質問に答えるのに役立ちます。

  • どのポートがアクティブに接続をリッスンしているか?
  • SYN_RECVTIME_WAIT 状態でスタックしている接続が多すぎないか?
  • 特定のポートを使用しているプロセス(PID)はどれか?
  • 予期しないアウトバウンド接続が発生していないか?

ソケット統計を調べることで、ネットワーク設定の問題を迅速に除外したり、接続処理に関連するリソース競合を特定したりできます。

レガシーツール: netstat

netstat は、何十年にもわたってネットワーク接続、ルーティングテーブル、インターフェース統計、マスカレード接続を表示するための標準ユーティリティでした。多くの最新システムでは ss に取って代わられていますが、広く利用可能であり、長年の管理者には馴染み深いツールです。

一般的な netstat の例

netstat で最もよく使われるフラグは、包括的な概要を提供します。

フラグ 説明
-a すべてのソケット(リッスン中および非リッスン中)を表示
-n ホスト名やサービス名を解決せずに数値アドレスを表示(出力を高速化)
-t TCP接続を表示
-u UDP接続を表示
-l リッスン中のソケットのみを表示
-p ソケットに関連付けられたPID/プログラム名を表示(root権限が必要)

例: すべてのアクティブなTCP接続を数値で表示

sudo netstat -ant

例: ポート80(HTTP)でリッスンしているものを検索

sudo netstat -tulpen | grep ':80'

接続状態の理解(netstat)

netstat の出力には、しばしば State 列が含まれます。注目すべき主要な状態は以下の通りです。

  • LISTEN: 着信接続を待機中。
  • ESTABLISHED: アクティブでオープンな接続。
  • TIME_WAIT: クローズ後、遅延パケットが処理されるのを確実にするために短時間待機しているソケット。
  • SYN_RECV: スリーウェイハンドシェイクの最終確認応答を待機中(過剰な場合はSYNフラッド攻撃を示す可能性あり)。

netstat に関する警告: netstat はしばしば /proc/net/* ファイルの解析に依存しており、特にアクティブな接続数が非常に多い(数千)システムでは遅くなる可能性があります。これが ss が開発された主な理由です。

現代の代替ツール: ss(ソケット統計)

ss ユーティリティは netstat よりも大幅に高速です。なぜなら、Netlinkソケットを使用してカーネル空間から直接ソケット情報を取得し、低速なファイルシステムルックアップをバイパスするからです。

一般的な ss の例

ss のフラグ構造は netstat と非常に似ており、容易な移行を促進します。

フラグ 説明
-a すべてのソケットを表示
-n 数値アドレスを表示
-t TCPソケットを表示
-u UDPソケットを表示
-l リッスン中のソケットを表示
-p プロセス情報(PID/プログラム)を表示

例: すべてのアクティブなTCP接続を数値で表示(netstat -ant と同等)

ss -ant

例: ポート443(HTTPS)でリッスンしているものを検索

sudo ss -tulpen | grep ':443'

ss による高度なフィルタリング

ss の最大の利点の一つは、接続状態に対して直接フィルタリングできることです。これは netstat の出力を grep にパイプするよりもはるかに効率的です。

接続状態によるフィルタリング

ss コマンド内で直接 state オプションを使用できます。これは接続の蓄積を診断するのに非常に便利です。

現在 TIME-WAIT 状態にあるすべてのソケットを検索:

ss -tan state time-wait

SYN-SENT 状態にあるすべてのソケットを検索(サーバーの応答を待つクライアント側):

ss -tan state syn-sent

ポートまたはアドレスによるフィルタリング

宛先または送信元アドレス/ポートによるフィルタリングは簡単です。

ポート22(SSH)宛ての確立された接続を表示:

ss -tn state established '( dport = :22 or sport = :22 )'

特定のローカルIPアドレスに関連する接続を表示:

ss -ant '( daddr = 192.168.1.100 or saddr = 192.168.1.100 )'

パフォーマンス分析: netstat vs. ss の比較

トラブルシューティング時、ツールの選択はしばしば速度と詳細さに帰着します。

機能 netstat ss
速度 遅い(ファイルを読み込む) はるかに高速(Netlinkソケットを使用)
構文 成熟しており、ドキュメントが豊富 類似のフラグ、新しい特定オプション
フィルタリング grep へのパイプが必要 ネイティブの状態およびアドレスフィルタリングをサポート
情報の深さ 基本には十分 ソケットバッファサイズなどの詳細情報(TCP Info)
可用性 ほぼ普遍的 最新のLinuxディストリビューションで標準

遅い接続確立の診断

クライアントが接続の遅さを報告する場合、ハンドシェイクを待ってスタックしているソケットがないか確認します。ss を使用するのがこれを判断する最速の方法です。

  1. 高い SYN-RECV 数を確認: これはサーバーが接続要求を受信しているがハンドシェイクを完了していないことを示唆し、多くの場合リソース不足や高トラフィック負荷が原因です。
    ss -s | grep syn-rec
    
  2. 高い SYN-SENT 数を確認: サーバー自体が多くの接続を開始している場合(例:データベースや他のAPIへのクライアントとして動作)、応答を待っていることを示します。
    ss -s | grep syn-sent
    

どちらのカテゴリでも持続的に高い数値が見られる場合は、それを結論ではなく手がかりとして扱います。SYN-SENT は、リモートホストがダウンしている、ルートが間違っている、ファイアウォールが静かにトラフィックをドロップしている、またはリモートサービスが過負荷であることを意味する可能性があります。SYN-RECV は、サーバーが負荷下にある、パケットが失われている、またはクライアントが接続を開いて完了していないことを意味する可能性があります。

実践的なトリアージフロー

誰かが「アプリが遅い」と言ったとき、私は通常、短く再現可能なパスから始めます。

sudo ss -tulpen
ss -s
sudo ss -tan state established '( sport = :443 or dport = :443 )' | head
sudo ss -tan state syn-recv
sudo ss -tan state time-wait | head

最初のコマンドは、期待されるサービスが実際にリッスンしていることを確認し、所有プロセスを表示します。サマリーは、ホストが驚くべき数のTCPソケットを持っているかどうかを示します。フィルタリングされた確立済み接続のコマンドは、実際のクライアントトラフィックがポートに接続されていることを証明します。syn-recvtime-wait のチェックは、接続のセットアップまたは接続のチャーンが注目に値するかどうかを示します。

例えば、ユーザーが新しいリクエストが数秒間ハングすると訴えるNginxリバースプロキシを想像してください。sudo ss -tulpen | grep ':443' は、NginxがHTTPSリスナーを所有していることを確認します。ss -s は大きなTCP合計を示し、sudo ss -tan state syn-recv '( sport = :443 )' は同じ送信元範囲から行を返し続けます。これは自動的に攻撃を証明するものではありませんが、ロードバランサーのヘルスチェック、上流のパケットロス、SYNバックログのプレッシャー、ファイアウォールログ、そしておそらくレート制限を調べるように導きます。

次に、同じプロキシに SYN_RECV ソケットがほとんどないが、上流データベースのポート 5432 への確立された接続が多数あると想像してください。これは、パブリックHTTPSからデータベースパスへと注意を向けさせます。

sudo ss -tanp '( dport = :5432 or sport = :5432 )'

所有プロセスがアプリケーションであり、カウントが上昇し続ける場合、次の有用な質問は、アプリケーションが接続をリークしているのか、遅いクエリを待っているのか、プールへの接続の返却に失敗しているのかです。ss はそのアプリケーションレベルの質問には答えませんが、正しい部屋に連れて行ってくれます。

パニックにならずに TIME_WAIT を読む

TIME_WAIT は正常なTCP状態であり、それ自体はエラーではありません。多数の短命な接続を処理するサーバーは、当然 TIME_WAIT ソケットを示します。これらは、古い接続からの遅延パケットが新しい接続と混同されるのを防ぐために存在します。

有用な質問は、TIME_WAIT がワークロードと一致するかどうかです。すべての小さなリクエストに対して新しいHTTP接続を開くバッチジョブは、TIME_WAIT の波を生み出す可能性があります。キープアライブを使用すべきだが使用していないサービスも同様です。カーネル設定をチューニングする前に、アプリケーションが接続を再利用できるか、HTTPキープアライブを有効にできるか、適切なクライアントプールを使用できるかを確認してください。

TIME_WAIT を「修正」するために盲目的にTCP sysctlを変更することを提案する古いアドバイスには注意してください。一部の設定はカーネルバージョンに依存し、時間の経過とともに削除または推奨されなくなったものもあり、NATやロードバランサーの背後で微妙な障害を引き起こすものもあります。まず、なぜ接続が短命なのかを理解することから始めてください。

ローカルとリモートのプレッシャーを確認する

時間を節約できる詳細の一つは、ローカルホストが主に接続を受け入れているのか、主に接続を行っているのかです。フロントエンドプロキシは通常、ローカルポートが 80 または 443 である多くの接続を持ちます。データベースやAPIと通信するアプリケーションサーバーは、リモートポートが 543233066379、または 443 である多くの接続を持つ場合があります。

ローカルリスナーとインバウンドトラフィックの場合:

sudo ss -tan '( sport = :443 )'

依存関係へのアウトバウンドトラフィックの場合:

sudo ss -tan '( dport = :6379 )'

この区別により、その後の会話が変わります。インバウンドHTTPSが積み上がっている場合、ロードバランサー、TLS終端、ワーカー制限、またはクライアントの動作を調査する必要があるかもしれません。アウトバウンドのRedis接続が積み上がっている場合、ローカルアプリケーションがクライアント接続を作成しすぎているか、Redisを待っているか、過度にリトライしている可能性があります。

数百行を読まずに簡単なカウントが必要な場合、ss をシンプルなシェルツールと組み合わせます。

sudo ss -tan state established '( dport = :443 )' | wc -l
sudo ss -tan state established '( dport = :5432 )' | wc -l

カウントにはヘッダー行が含まれるため、完全なメトリクスではありません。トリアージには、それでも有用です。インシデント中に数値が毎分倍になる場合、単一のスナップショットよりも強力なシグナルが得られます。

コンテナとネットワーク名前空間

コンテナ化されたホストでは、コマンドを実行する場所に注意してください。ホスト上で ss を実行すると、ホストのネットワーク名前空間と公開ポートが表示されますが、プロセスがコンテナ内で見ているものと同じビューが表示されない場合があります。サービスがコンテナ内で実行されている場合は、両方のビューを比較してください。

sudo ss -tulpen
docker exec <container> ss -tulpen

Kubernetesの場合は、ホストレベルのリスナーにはノードビューを、Podのネットワーク名前空間には kubectl exec を使用します。コンテナ内でポートが開いていても、ホスト、サービス、イングレス、またはネットワークポリシーがトラフィックの到達を妨げている可能性があります。ss はローカルの真実を示すツールであり、エンドツーエンドの接続テストではありません。

ネットワークトラブルシューティングのベストプラクティス

  1. 常に -n を使用する: パフォーマンスのトラブルシューティングやスクリプト作成時には、数値フラグ(-n)を使用してDNS解決の遅延を回避します。これにより診断が遅くなる可能性があります。
  2. ss を優先する: デフォルトのツールとして ss を採用します。ss が利用できないレガシーシステムでのみ netstat を予約します。
  3. PIDを確認するにはrootで実行する: どのプログラムがポートを使用しているかを確認するには、両方のユーティリティで -p フラグを使用する際に、一般的に sudo またはroot権限が必要です。
  4. インターフェース統計を確認する: インターフェースカウンターを忘れないでください。ip -s link show <interface_name> を使用して、ドロップされたパケットやエラーを確認します。これらはソケットの問題ではなく、物理層の問題を示している可能性があります。
  5. スナップショットを比較する: 1つの ss 出力は写真です。1分間隔で取得した2つの出力は、状況が拡大しているのか、縮小しているのか、安定しているのかを教えてくれます。
  6. 正確なフィルターを書き留める: インシデント中は、ss -tan '( dport = :5432 )' のような保存されたコマンドの方が、中途半端に覚えたgrepパイプラインよりも繰り返し実行して比較するのが簡単です。

報われる習慣はシンプルです。リスナーから始め、接続状態に移り、所有プロセスを特定し、次のステップがアプリ、ネットワークパス、ファイアウォール、カーネルのどこに属するかを判断することです。