深夜の帯域逼迫という悪夢:決済システムで起きた実話
金曜日の深夜23時15分、PagerDutyのアラートがけたたましく鳴り響きました。運用中のAPI Gatewayと決済ゲートウェイクラスタのレイテンシが、平時の45msから一気に2.8秒へと急激に悪化。Nginxでの504 Gateway Timeoutエラー率は18%に達していました。
Grafanaを開くと、ネットワークトラフィックのグラフが真っ赤に跳ね上がっていました。スイッチ側のNIC帯域は980Mbps(1Gbpsポートのほぼ上限)に達し、完全に枯渇。慌てて各サーバーへSSH接続し、iftopやnethogsを実行したものの、このアプローチではあまりにも場当たり的でした。40台近いマイクロサービス仮想マシンが稼働するクラスタで、1分1秒を争う障害発生中に1台ずつ手動でプロセスを調べていくなど不可能です。
システムは深刻なボトルネックに陥っていました。誰がデータを送信しているのか?どのプロトコルが回線を占有しているのか?外部インターネット向けなのか、それとも内部クラスタ間のトラフィックなのか?その時点では、すべてが完全な暗闇の中でした。
ネットワークが逼迫した際、なぜPrometheusやZabbixは無力なのか?
インシデント収束後、チームでポストモーテムを実施した結果、監視データに大きな盲点があることが浮き彫りになりました。
- 一般的なメトリクス監視(Prometheus node_exporter、Zabbixなど): 送受信バイト総数やパケット数/秒といった生のボリューム(量)しか計測できません。パケットがアプリケーション層(Layer 7)でどのようなデータを含んでいるかは一切把握できないのです。
- サービスログ: Nginxのアクセスログやiptablesのログは、TCPセッションが切断された後やパケットが破棄された時点で初めて記録されます。接続を張り続け、リアルタイムに帯域を食いつぶしている最中のインフライトなフロー(未完了の接続)に対しては、完全に手も足も出ません。
- DPI(Deep Packet Inspection)の欠如: 意図しないrsyncによるデータバックアップ、誤ってS3へ転送されたデータベースダンプ、さらにはDNSアンプ攻撃なども、ペイロードのヘッダーを分解・解析しない限り、通常のトラフィックと見分けがつきません。
ネットワークフロー分析における3つの選択肢
この課題を解決するため、よく用いられる3つのアプローチを検討しました。
- tcpdumpで生パケットをキャプチャし、Wiresharkで解析する:
tcpdump -i eth0 -w dump.pcapを実行する方法です。ビット単位で極めて詳細に調査できますが、キャプチャファイルは3分足らずで10GB以上に膨れ上がってディスクI/Oを圧迫し、高負荷状態でのリアルタイム分析には到底耐えられません。 - NetFlow / sFlowをELKスタックに集約する: ルーターからLogstashへフローを転送し、Elasticsearchに蓄積する構成です。高機能ではあるものの、メモリ消費が非常に激しく、この用途専用のElasticsearchクラスタだけでも最低16GBのRAMを消費します。さらにパイプラインの構築が煩雑な上、可視化までに1〜2分のタイムラグが生じます。
- ntopngとnDPIを組み合わせて構築する: ntopngはパケットキャプチャとダッシュボードによる可視化を単体で同時にこなします。内蔵されたnDPIライブラリにより、インメモリでLayer 7プロトコルを即座に識別・分解し、Redisで一時的なフロー状態を保持しながら、500MB〜1GB程度の極めて軽量なリソース消費でリアルタイムなグラフ表示を実現します。
Ubuntu / Debian環境におけるntopngの実践的な導入手順
以下は、ネットワーク監視専用サーバー(スイッチのSPAN/ミラーポート接続、またはLinuxゲートウェイ直下)にntopngを構築した際の実践手順です。
ステップ1:リポジトリの追加とntopngのインストール
最新のnDPIシグネチャを利用するため、Ubuntu標準リポジトリではなく、ntop公式のリポジトリを使用します。
# 1. 前提ツールのインストール
sudo apt update && sudo apt install -y software-properties-common wget lsb-release gnupg
# 2. ntop公式リポジトリパッケージの取得と登録
wget https://packages.ntop.org/apt/$(lsb_release -rs)/all/apt-ntop.deb
sudo dpkg -i apt-ntop.deb
sudo apt update
# 3. ntopngおよび状態キャッシュ用Redisのインストール
sudo apt install -y redis-server ntopng
ステップ2:監視対象インターフェースの設定
設定ファイル /etc/ntopng/ntopng.conf を編集します。
sudo nano /etc/ntopng/ntopng.conf
デフォルトの記述を整理し、本番環境向けに最適化した設定を記述します。
# Web UIのポート番号
-w=3000
# キャプチャ対象のNIC ('ip a' コマンド等で確認)
-i=eth0
# Inbound / Outbound / Local のトラフィック方向を識別するための内部IPレンジ定義
-m=192.168.1.0/24,10.10.0.0/16
# RRDメトリクスおよび分析データの保存先ディレクトリ
-d=/var/lib/ntopng
# 高トラフィック時のスレッド停止を防ぐため、自動逆引きDNS検索を無効化
-n=1
特に -n=1 のオプションは極めて重要です。数万規模のコネクションが同時に発生する高負荷時に、ntopngがIPごとにDNS名前解決を試行すると、パケットキャプチャのプロセス全体がフリーズしてしまいます。
ステップ3:サービスの起動とログイン確認
まずRedisを起動し、その後にntopngを有効化・起動します。
sudo systemctl enable redis-server ntopng
sudo systemctl restart redis-server
sudo systemctl restart ntopng
# サービスが正常に稼働しているか確認
sudo systemctl status ntopng
ブラウザから http://<サーバーのIP>:3000 にアクセスします。初期アカウントは admin / admin です。初回ログイン時に新しいパスワードへの変更が強制されます。
ステップ4:「アラート疲れ(Alert Fatigue)」への対策 — 通知スパムを防ぐ運用設計
本番環境へntopngを導入した最初の1週間は、まさにアラートの嵐でした。パケットの順序不一致や軽微なジッター、未知のDNSクエリに至るまで、デフォルトの全ルールが有効化されていたためです。結果として、Slackボットから1日2,300件以上の通知が爆撃のように届き、3日目にはチーム全員が通知チャンネルをミュートにしてしまいました。これでは監視システムを導入した意味がありません。
この状況を根本から是正するため、以下の3点に絞ってチューニングを実施しました。
- ホストプールのグループ化: 内部クラスタ(データベースのレプリケーションやCephストレージなど)を専用プールにまとめます。Settings > Alert Entities からそれらのプール間における高帯域アラートを無効化しました。ノード間で数百GB規模のデータ同期が走るのは正常な動作だからです。
- ゲートウェイ向けのFlow Floodしきい値緩和: リバースプロキシ(NginxやHAProxy)が数万の同時接続を処理するのは当然です。対象ホスト個別のしきい値設定を開き、Max Number of Flows をデフォルトの8倍まで引き上げることで、SYN Flood攻撃と誤検知されるのを防ぎました。
- アクション可能なアラートのみを通知: Blacklisted IP Contacts、内部ポートスキャンの兆候となる TCP Connection Refused burst、そして DNS Tunneling など、実害につながるものに限定しました。「オンコール担当が今すぐ起きて対応すべきでないアラート」は、すべて通知をオフにします。
運用現場からのまとめ
ntopngの導入によって、あの深夜に発生した帯域逼迫の真相も完全に解明されました。原因は、自動バックアップ用cronjobの記述ミスでした。内部で圧縮してからセカンダリ回線へ流すべきところを、40GBもの非圧縮生ダンプデータをパブリックAPIゲートウェイ経由でそのまま転送していたのです。
現在では、帯域アラートが発生しても Flows > Top Talkers タブを開くだけで対応可能です。わずか20秒足らずで、どのIPがどのポートを使い、何のアプリケーションプロトコルで帯域を圧迫しているのかを一元特定できるようになり、深夜にSSHで原因を手探りする不毛な作業とは完全に決別できました。

