2026年7月23日

2026年7月23日

Nginxの接続数グラフ(Connections over Time)の読み方|stub_statusの値と異常の見分け方

監視ツールの「Connections over Time」のような、Nginxの接続数を時系列で表したグラフは、ほとんどの場合、Nginxの stub_status モジュールが出す数値をもとにしています。グラフを正しく読むには、まずその数値が何を数えているかを知る必要があります。

この記事では、stub_statusの各値の意味、グラフの作り方、よくある形とその原因の見分け方を説明します。内容は2026年10月時点のnginx.orgの公式ドキュメントと、NGINXが公開している nginx-prometheus-exporter に合わせています。

stub_statusの値の意味

stub_statusを有効にしたURLを開くと、次のような出力が得られます。

Active connections: 291
server accepts handled requests
 16630948 16630948 31070465
Reading: 6 Writing: 179 Waiting: 106

公式ドキュメントでの定義は次のとおりです。

値 種類 意味
Active connections 現在の数 クライアントとの接続の数。Waitingの接続も含む
accepts 起動からの累計 受け付けたクライアント接続の総数
handled 起動からの累計 処理した接続の総数。通常は accepts と同じで、worker_connections の上限などに達したときだけ少なくなる
requests 起動からの累計 クライアントからのリクエストの総数
Reading 現在の数 リクエストヘッダーを読んでいる接続の数
Writing 現在の数 クライアントにレスポンスを書き出している接続の数
Waiting 現在の数 次のリクエストを待っているアイドルな接続の数(キープアライブ中の接続)

グラフを読むうえで大事な点は次の3つです。

  • Activeは、おおむねReading・Writing・Waitingの合計になる(それぞれ別々に数えているので、ぴったり一致しないことがある)。Activeの山が大きくても、その大半がWaitingなら、アイドルな接続が多いだけで負荷は高くない
  • accepts・handled・requestsは累計値なので、そのままグラフにすると右肩上がりの線になる。1秒あたりの増え方(レート)に直して見る
  • 数えているのはクライアントとの接続で、Nginxから裏側(PHP-FPMやアプリケーションサーバー)への接続は含まない

なお、stub_statusのページを見ている自分の接続も、その瞬間はWritingとして数えられます。アクセスの無いサーバーでもWritingが1になるのはこのためです。

stub_statusを有効にする

stub_statusは標準のビルドには含まれず、--with-http_stub_status_module を付けてビルドする必要があります。nginx.orgのパッケージやUbuntu・Debianのパッケージには通常含まれているので、次のコマンドで確認します。

nginx -V 2>&1 | grep -o with-http_stub_status_module

with-http_stub_status_module と表示されれば使えます。外部に公開しないよう、ローカルホストだけで待ち受けるserverブロックに設定します。たとえば /etc/nginx/conf.d/status.conf を作ります。

server {
    listen 127.0.0.1:8080;

    location = /stub_status {
        stub_status;
        access_log off;
        allow 127.0.0.1;
        deny all;
    }
}
sudo nginx -t
sudo systemctl reload nginx
curl http://127.0.0.1:8080/stub_status

グラフを作る

Prometheusとnginx-prometheus-exporterを使う

継続的に監視するなら、NGINXが公開している nginx-prometheus-exporter でstub_statusの値をPrometheusの形式に変換し、PrometheusとGrafanaでグラフにする方法が一般的です。Dockerで動かす場合の例です。

docker run -d --name nginx-exporter --network host \
  nginx/nginx-prometheus-exporter:1.5.1 \
  --nginx.scrape-uri=http://127.0.0.1:8080/stub_status \
  --web.listen-address=127.0.0.1:9113

エクスポーターは http://127.0.0.1:9113/metrics で値を出します。イメージのタグは、GitHubのリリース一覧で最新版を確認して指定してください。Dockerを使わない場合は、GitHubのリリースからバイナリを入手してsystemdで動かします。

Prometheusの設定(prometheus.yml)に取得先を追加します。

scrape_configs:
  - job_name: nginx
    static_configs:
      - targets: ['127.0.0.1:9113']

エクスポーターが出す値と、stub_statusの対応は次のとおりです。

メトリクス 種類 stub_statusの値
nginx_connections_active Gauge Active connections
nginx_connections_reading Gauge Reading
nginx_connections_writing Gauge Writing
nginx_connections_waiting Gauge Waiting
nginx_connections_accepted Counter accepts
nginx_connections_handled Counter handled
nginx_http_requests_total Counter requests
nginx_up Gauge 最後の取得が成功したか(1か0)

Grafanaのパネルには、次のようなPromQLを使います。

# 現在の接続数(状態別に並べる)
nginx_connections_reading
nginx_connections_writing
nginx_connections_waiting

# 1秒あたりの新規接続数とリクエスト数
rate(nginx_connections_accepted[5m])
rate(nginx_http_requests_total[5m])

# 処理されずに落とされた接続(0 が正常)
rate(nginx_connections_accepted[5m]) - rate(nginx_connections_handled[5m])

# 1接続あたりのリクエスト数(キープアライブの再利用の度合い)
rate(nginx_http_requests_total[5m]) / rate(nginx_connections_accepted[5m])

ReadingとWritingとWaitingを積み上げグラフにすると、合計がおおむねActiveと重なり、内訳の変化が読みやすくなります。

とりあえず記録だけしたい場合

監視基盤が無いサーバーで、短期間の傾向を見たいだけなら、stub_statusを定期的にCSVに記録する方法もあります。

while true; do
  s=$(curl -s http://127.0.0.1:8080/stub_status)
  echo "$(date +%FT%T),$(echo "$s" | awk '/^Active/{a=$3} /^ [0-9]/{acc=$1; req=$3} /^Reading/{print a","$2","$4","$6","acc","req}')"
  sleep 10
done >> /var/tmp/nginx_conn.csv

列は「時刻, Active, Reading, Writing, Waiting, accepts累計, requests累計」です。表計算ソフトで開いてグラフにできます。累計の列は、前の行との差を取ってから見ます。

よくあるグラフの形と原因

グラフの形 考えられる原因 確認すること
Activeが高いが、ほとんどがWaiting キープアライブ中のアイドル接続が多いだけ。異常ではないことが多い keepalive_timeout(既定75秒)。短くするとWaitingは減るが、再接続が増える
Writingが増え続ける 裏側の応答が遅い(PHP-FPMやデータベース)、または大きなファイルを遅い回線に送っている $request_time や $upstream_response_time をログに出して遅いリクエストを探す。PHP-FPMの空きプロセス
Readingが多い リクエストヘッダーを送り終えない接続が多い。遅い回線や、接続を占有する攻撃(Slowloris型)の可能性 アクセスログの送信元、client_header_timeout
acceptsとhandledの差が増える worker_connections か、開けるファイル数の上限に達して接続を落としている エラーログの「worker_connections are not enough」、worker_rlimit_nofile
新規接続数とリクエスト数が同時に急増 アクセスの集中(告知、クローラー、攻撃) アクセスログの送信元IPとURL、ユーザーエージェント
決まった時刻に山ができる cronのバッチ、外部の監視、クローラーの巡回 山の時刻のアクセスログ
1接続あたりのリクエスト数が1に近い キープアライブが効いていない(クライアント側か、手前のロードバランサーが毎回接続を切っている) keepalive_timeout、ロードバランサーの設定

上限との比較

1つのワーカープロセスが同時に開ける接続の数は worker_connections で決まり、既定値は512です。この数には、クライアントとの接続だけでなく、裏側のサーバーへのプロキシ接続なども含まれます。リバースプロキシとして使っている場合は、1つのリクエストでクライアント側と裏側の2つの接続を使うことがあるので、Activeの値が「ワーカー数 × worker_connections」の半分程度に近づいてきたら、設定の見直しを検討します。

# 現在の設定値を確認する
sudo nginx -T 2>/dev/null | grep -E 'worker_processes|worker_connections|worker_rlimit_nofile|keepalive_timeout'

まとめ

  • 接続数のグラフの多くはstub_statusの値がもとになっている
  • Activeはおおむね Reading + Writing + Waiting。Waitingが多いだけなら負荷は高くない
  • accepts・handled・requestsは累計値なので、レートに直して見る
  • Writingの増加は裏側の遅延、acceptsとhandledの差は接続数の上限を疑う
  • stub_statusはローカルホストだけに公開し、継続監視にはnginx-prometheus-exporterとPrometheusを使う

関連記事:

お気軽にご相談ください

お見積りへ お問い合わせへ
▲