Nginx 高同時接続設定とパフォーマンス最適化の実践
Nginx 高同時接続:アーキテクチャから実践まで
Nginxはイベント駆動・非ブロッキングI/Oアーキテクチャにより、単一サーバーで数万の同時接続を処理できます。しかし、デフォルト設定ではその潜力を十分に発揮できず、本番ワークロードに向けた深いチューニングが必要です。
| 最適化領域 | キーパラメータ | 影響範囲 |
|---|---|---|
| プロセスモデル | worker_processes, worker_connections | 同時接続容量 |
| イベントモデル | use epoll, multi_accept | イベント処理効率 |
| 負荷分散 | upstream, proxy_next_upstream | トラフィック分散とフォールトトレランス |
| バッファとタイムアウト | proxy_buffers, keepalive_timeout | メモリと接続再利用 |
| 圧縮 | gzip, gzip_comp_level | 転送帯域幅 |
| セキュリティ | limit_req, limit_conn | トラフィック防護 |
1. Nginxアーキテクチャ:イベント駆動とワーカープロセス
Master-Workerモデル
NginxはMaster-Workerマルチプロセスアーキテクチャを採用:
- Masterプロセス:設定読み込み、ポートバインド、Worker管理(fork/シグナル/リロード)
- Workerプロセス:独立してリクエストを処理、1つのWorkerクラッシュが他に影響しない
# Nginxプロセス構造の確認
# ps aux | grep nginx
# root 1234 nginx: master process
# www-data 1235 nginx: worker process
# www-data 1236 nginx: worker process
イベント駆動モデル
NginxはReactorパターンに基づき、I/O多重化技術を使用:
| I/Oモデル | プラットフォーム | パフォーマンス |
|---|---|---|
epoll |
Linux | 最適、O(1)イベント通知 |
kqueue |
FreeBSD/macOS | 優秀、epollに類似 |
select |
汎用 | 低い、fd_set上限1024 |
poll |
汎用 | 普通、上限なし但し線形スキャン |
events {
use epoll;
worker_connections 65535;
multi_accept on;
accept_mutex off;
}
multi_accept onはWorkerが全ての新規接続を一度に受け取るようにし、システムコールを削減。accept_mutex offは高同時接続時のサンダリングハード問題を回避(Linux 3.9+はSO_REUSEPORTをサポート)。
2. 核心同時接続設定
worker_processes
# CPUコア数を自動検出(推奨)
worker_processes auto;
# または手動指定(通常CPUコア数またはその2倍)
worker_processes 8;
チューニングのヒント:
- 通常
autoに設定し、CPUコア数と一致させる - CPU集約型ワークロード(SSL、gzip):コア数に一致
- I/O集約型ワークロード:2倍のコア数を検討
worker_connections
events {
worker_connections 65535;
}
最大同時接続数 = worker_processes × worker_connections。システムのファイルディスクリプタ制限も調整が必要:
# 一時的な変更
ulimit -n 65535
# 永続的な変更(/etc/security/limits.conf)
* soft nofile 65535
* hard nofile 65535
worker_rlimit_nofile
# ワーカープロセスあたりの最大ファイルディスクリプタ数
worker_rlimit_nofile 65535;
完全な基本設定
user www-data;
worker_processes auto;
worker_rlimit_nofile 65535;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
use epoll;
worker_connections 65535;
multi_accept on;
accept_mutex off;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
keepalive_requests 100;
}
3. 負荷分散アルゴリズムの詳細
基本設定
upstream backend {
server 10.0.0.1:8080 weight=5;
server 10.0.0.2:8080 weight=3;
server 10.0.0.3:8080 weight=2;
server 10.0.0.4:8080 backup;
}
5つのスケジューリングアルゴリズムの比較
| アルゴリズム | ディレクティブ | 特徴 | ユースケース |
|---|---|---|---|
| ラウンドロビン | (デフォルト) | 順次分配、均等 | バックエンド性能が同一 |
| 加重ラウンドロビン | weight=N |
重み比で分配 | バックエンド性能に差異 |
| 最小接続 | least_conn |
接続数が最も少ないサーバーに優先分配 | 長接続/リクエスト時間に差異 |
| IPハッシュ | ip_hash |
同一IPを同一サーバーに固定 | セッション維持が必要 |
| ランダム | random |
ランダム選択 | ステートレスサービス |
| 一貫性ハッシュ | hash $key consistent |
一貫性ハッシュリング | キャッシュサーバー |
least_conn設定
upstream api_backend {
least_conn;
server 10.0.0.1:8080;
server 10.0.0.2:8080;
server 10.0.0.3:8080;
}
ip_hash設定
upstream web_backend {
ip_hash;
server 10.0.0.1:8080;
server 10.0.0.2:8080;
server 10.0.0.3:8080;
}
注意:
ip_hashはbackupとweightをサポートしません。本番環境では一貫性ハッシュの使用を推奨。
一貫性ハッシュ設定
upstream cache_backend {
hash $request_uri consistent;
server 10.0.0.1:8080;
server 10.0.0.2:8080;
server 10.0.0.3:8080;
}
4. アップストリームヘルスチェック
パッシブヘルスチェック(内蔵)
upstream backend {
server 10.0.0.1:8080 max_fails=3 fail_timeout=30s;
server 10.0.0.2:8080 max_fails=3 fail_timeout=30s;
server 10.0.0.3:8080 max_fails=3 fail_timeout=30s;
}
| パラメータ | 意味 | デフォルト |
|---|---|---|
max_fails |
失敗回数の閾値、超過で利用不可とマーク | 1 |
fail_timeout |
利用不可マークの持続時間 | 10s |
アクティブヘルスチェック(nginx-upstream-check-module)
upstream backend {
server 10.0.0.1:8080;
server 10.0.0.2:8080;
check interval=3000 rise=2 fall=3 timeout=1000 type=http;
check_http_send "HEAD /health HTTP/1.0\r\n\r\n";
check_http_expect_alive http_2xx http_3xx;
}
proxy_next_upstreamフォールトトレランス
proxy_next_upstream error timeout http_502 http_503 http_504;
proxy_next_upstream_timeout 10s;
proxy_next_upstream_tries 3;
5. バッファとタイムアウトのチューニング
プロキシバッファ
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 16k;
proxy_busy_buffers_size 32k;
| パラメータ | 意味 | 推奨値 |
|---|---|---|
proxy_buffer_size |
レスポンスヘッダバッファサイズ | 4k-8k |
proxy_buffers |
レスポンスボディバッファ数とサイズ | 8 16k |
proxy_busy_buffers_size |
ビジーバッファサイズ | proxy_buffers合計の半分 |
タイムアウト設定
proxy_connect_timeout 5s;
proxy_send_timeout 10s;
proxy_read_timeout 30s;
client_body_timeout 12s;
client_header_timeout 12s;
send_timeout 10s;
keepalive_timeout 65s;
keepalive_requests 100;
アップストリームKeepaliveコネクションプール
upstream backend {
server 10.0.0.1:8080;
server 10.0.0.2:8080;
keepalive 32;
keepalive_requests 100;
keepalive_timeout 60s;
}
server {
location / {
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_pass http://backend;
}
}
keepalive 32は各Workerがバックエンドとの32個のアイドル長接続を維持し、頻繁なTCPハンドシェイクを回避。
6. Gzip圧縮の最適化
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 1024;
gzip_http_version 1.1;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml
application/xml+rss
application/vnd.ms-fontobject
application/x-font-ttf
font/opentype
image/svg+xml;
gzip_buffers 16 8k;
gzip_disable "msie6";
| パラメータ | 説明 | 推奨値 |
|---|---|---|
gzip_comp_level |
圧縮レベル 1-9 | 4-6(CPUと圧縮率のバランス) |
gzip_min_length |
最小圧縮長 | 1024(小ファイルは圧縮で逆に大きくなる) |
gzip_types |
圧縮するMIMEタイプ | 必要に応じて追加、画像は除外 |
gzip_buffers |
圧縮バッファ | 16 8k |
7. 静的ファイルサービとキャッシュ
静的ファイル最適化
server {
listen 80;
server_name static.example.com;
root /var/www/static;
location / {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
open_file_cache max=10000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
expires 30d;
add_header Cache-Control "public, immutable";
}
location ~* \.(js|css)$ {
expires 7d;
add_header Cache-Control "public, immutable";
}
location ~* \.(jpg|jpeg|png|gif|ico|svg|webp)$ {
expires 365d;
add_header Cache-Control "public, immutable";
}
}
open_file_cacheの説明
| パラメータ | 意味 |
|---|---|
max=N |
キャッシュ最大ファイルディスクリプタ数 |
inactive=T |
キャッシュエントリの寿命 |
valid=T |
キャッシュ有効性チェック間隔 |
min_uses=N |
inactive期間内の最小アクセス回数 |
errors |
ファイル検索エラーをキャッシュするか |
8. SSL/TLSパフォーマンス最適化
セッションキャッシュ
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets on;
shared:SSL:10m— 全Workerが10MBのセッションキャッシュを共有、約40,000セッションをキャッシュ可能。
OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
完全なSSL設定
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/nginx/ssl/example.com.pem;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets on;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
ssl_buffer_size 4k;
}
9. レート制限と防護
リクエストレート制限(limit_req)
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/s;
server {
location /api/ {
limit_req zone=api_limit burst=200 nodelay;
proxy_pass http://backend;
}
}
| パラメータ | 意味 |
|---|---|
rate=100r/s |
IPあたり毎秒100リクエスト |
burst=200 |
200リクエストのバーストを許可 |
nodelay |
バーストリクエストを遅延させず、超過は即座に拒否 |
同時接続数制限(limit_conn)
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
server {
location /api/ {
limit_conn conn_limit 50;
proxy_pass http://backend;
}
}
帯域幅制限
location /download/ {
limit_rate 500k;
limit_rate_after 10m;
}
最初の10MBは速度制限なし、その後500KB/sに制限。
10. リバースプロキシ設定
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 16k;
}
location /ws/ {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 3600s;
}
}
11. 一般的なエラーのトラブルシューティング
502 Bad Gateway
原因:Nginxがバックエンドサービスに接続できない。
# バックエンドサービスが稼働しているか確認
curl -I http://10.0.0.1:8080/health
# Nginxエラーログの確認
tail -f /var/log/nginx/error.log | grep 502
# 一般的な原因:
# 1. バックエンドサービスが未起動またはクラッシュ
# 2. バックエンドポートの設定ミス
# 3. バックエンドの過負荷で接続拒否
# 4. SELinux/ファイアウォールによるブロック
504 Gateway Timeout
原因:バックエンドサービスのレスポンスタイムアウト。
# タイムアウトを増加
proxy_connect_timeout 10s;
proxy_read_timeout 60s;
proxy_send_timeout 60s;
# トラブルシューティング手順
# 1. バックエンドのレスポンス時間を確認
curl -o /dev/null -s -w "time_total: %{time_total}\n" http://backend/api
# 2. バックエンドログでスロークエリを確認
# 3. ネットーク遅延を確認
ping -c 5 10.0.0.1
429 Too Many Requests
原因:レート制限ルールのトリガー。
# カスタムレート制限レスポンス
limit_req_status 429;
12. セキュリティ強化
セキュリティレスポンスヘッダ
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
DDoS緩和
limit_req_zone $binary_remote_addr zone=ddos:10m rate=30r/s;
limit_conn_zone $binary_remote_addr zone=ddos_conn:10m;
server {
limit_req zone=ddos burst=50 nodelay;
limit_conn ddos_conn 30;
client_body_buffer_size 16k;
client_max_body_size 1m;
client_header_buffer_size 1k;
large_client_header_buffers 4 8k;
}
機密パスのブロック
location ~ /\.(git|svn|env) {
deny all;
return 404;
}
location ~* /(wp-admin|phpmyadmin|adminer) {
deny all;
return 404;
}
13. パフォーマンスベンチマーク
wrkベンチマーク
# wrkのインストール
git clone https://github.com/wg/wrk.git
cd wrk && make && sudo cp wrk /usr/local/bin/
# ベンチマーク(12スレッド、400接続、30秒間)
wrk -t12 -c400 -d30s http://example.com/
# レイテンシ分布付き
wrk -t12 -c400 -d30s --latency http://example.com/
# POSTリクエストテスト
wrk -t4 -c200 -d10s -s post.lua http://example.com/api
abベンチマーク
# Apache Benchのインストール
# Ubuntu: apt install apache2-utils
# ベンチマーク(200同時接続、10000リクエスト)
ab -n 10000 -c 200 http://example.com/
# Keep-Alive付き
ab -n 10000 -c 200 -k http://example.com/
ベンチマーク結果の分析
| 指標 | 意味 | 参考値 |
|---|---|---|
| Requests/sec | 毎秒処理リクエスト数 | 静的アセット > 10000 |
| Latency (p99) | 99パーセンタイルレイテンシ | < 100ms |
| Transfer/sec | 毎秒転送データ量 | ワークロードに依存 |
| Socket errors | 接続エラー数 | 0であるべき |
14. FAQ
Q: worker_processesをautoに設定後、Worker数がCPUコア数と一致しない?
A: autoは/proc/cpuinfoから利用可能なコア数を読み取ります。コンテナでcgroup CPU制限が設定されている場合、Nginx 1.19+のみがcgroup制限を検出します。旧バージョンは手動設定が必要です。
Q: worker_connectionsを65535に設定後、実際の同時接続数が上がらない?
A: システム制限も調整が必要:ulimit -n、net.core.somaxconn、net.ipv4.tcp_max_syn_backlog、fs.file-max。
Q: ip_hashと一貫性ハッシュのどちらを選ぶべきか?
A: ip_hashはシンプルですがweight/backupをサポートせず、スケール時に大量のセッション移行が発生します。一貫性ハッシュはスケール時に隣接ノードのみ影響 — キャッシュ層に推奨。
Q: gzip_comp_levelはいくつに設定すべきか?
A: 4-6が最適。レベル1-3は圧縮率が低く、7-9はCPU消費が大幅に増加するが圧縮率の向上は微々たるもの。実際のテストではレベル6と9の圧縮率差は2-3%のみだが、CPU消費は50%以上増加。
Q: Nginxのリアルタイムステータスを監視するには?
A: stub_statusモジュールを有効化し、Prometheus + Grafanaまたはngxtopツールでリアルタイム監視。
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
Q: リクエストを落とさずNginxをグレースフルリロードするには?
A: nginx -s reloadを使用。Masterが設定をリロードし、新しいWorkerを起動、古いWorkerは現在のリクエスト処理完了後に終了。
おすすめツール:/encode/base64で設定ファイルをエンコード、/encode/hashで設定ハッシュチェックサムを生成、/json/formatでNginx JSONログをフォーマット。
ブラウザローカルツールを無料で試す →