高トラフィックWebサイトのためのNginxパフォーマンスチューニング必須チェックリスト

ワーカー、接続、バッファ、キャッシュ、圧縮、ログ、タイムアウト、TLS、静的ファイルに関する実践的なNginxパフォーマンスチェックリスト。

高トラフィックWebサイトのためのNginxパフォーマンスチューニング必須チェックリスト

Nginxのパフォーマンスチューニングは、推測ではなくチェックリストとして扱うのが最も簡単です。まず、Nginxが受け入れられるトラフィック量を決定する制限から始め、次にバッファリング、キャッシュ、圧縮、ロギング、タイムアウト、TLS、そしてその背後にあるバックエンドサービスへと進みます。

ここにあるすべてのディレクティブを一度に本番環境に貼り付けないでください。優れたNginxパフォーマンスチューニングチェックリストは、何を確認すべきか、なぜそれが重要なのか、そしてやりすぎると何が問題になるのかを判断するのに役立ちます。主に静的なドキュメントサイトに適した設定は、ロングポーリングAPIやファイルアップロードサービスには適していません。

1. ワーカープロセスと接続の最適化

Nginxはマスター・ワーカープロセスモデルを活用しています。マスタープロセスは設定を読み込み、ワーカープロセスを管理します。ワーカープロセスは実際のクライアントリクエストを処理します。これらを適切に設定することで、同時実行性とリソース使用率を大幅に向上させることができます。

worker_processes

このディレクティブは、Nginxが生成するワーカープロセスの数を決定します。一般的に、autoに設定すると、NginxがCPUコア数を検出し、同じ数のワーカープロセスを生成するため、一般的なベストプラクティスとなります。

worker_connections

1つのワーカープロセスが開くことができる最大同時接続数を定義します。この設定は、worker_processesと組み合わせて、Nginxが処理できる理論上の最大同時接続数(worker_processes * worker_connections)を決定します。

multi_accept

ワーカープロセスが一度に複数の新しい接続を受け入れることを可能にし、高負荷時の潜在的なボトルネックを防ぎます。

# /etc/nginx/nginx.conf

worker_processes auto; # 通常は 'auto' またはCPUコア数に設定

events {
    worker_connections 1024; # サーバー容量と想定負荷に基づいて調整
    multi_accept on;
}

ヒント: CPUが常に高い場合、worker_connectionsを増やしてもそれだけでは解決しません。まず、CPUがTLSハンドシェイク、圧縮、ロギング、正規表現を多用するルーティング、またはアップストリームアプリケーションのいずれかに起因しているかどうかを確認してください。

2. 効率的な接続管理

Nginxがネットワーク接続を処理する方法を最適化すると、オーバーヘッドが削減され、応答性が向上します。

keepalive_timeout

キープアライブクライアント接続を開いたままにする時間を指定します。接続を再利用すると、新しいTCP接続とSSLハンドシェイクの確立にかかるオーバーヘッドが削減されます。アプリケーションの対話性に応じて、一般的な値は15〜65秒です。

sendfile

ファイル記述子間でのデータの直接転送を有効にし、ユーザースペースのバッファリングをバイパスします。これにより、静的ファイルを提供する際のパフォーマンスが大幅に向上します。

tcp_nopush

sendfileと連携します。Nginxは、HTTPヘッダーとファイルの先頭を1つのパケットで送信しようとします。その後、データを完全なパケットで送信します。これにより、送信されるパケット数が削減されます。

tcp_nodelay

Nginxに、バッファリングせずにデータを利用可能になり次第送信するよう指示します。これは、スループットの最大化よりも低レイテンシが重要なインタラクティブアプリケーション(チャットアプリケーションやリアルタイム更新など)に有益です。

http {
    keepalive_timeout 65; # キープアライブ接続を65秒間維持
    sendfile on;
    tcp_nopush on; # sendfile on が必要
    tcp_nodelay on; # 動的コンテンツのプロキシに便利
}

3. バッファの最適化

Nginxはバッファを使用して、クライアントリクエストとアップストリームサーバー(アプリケーションサーバーなど)からの応答を処理します。これらのバッファを適切にサイジングすることで、不要なディスクI/Oを防ぎ、メモリ使用量を削減し、スループットを向上させることができます。

クライアントバッファ

  • client_body_buffer_size: クライアントリクエスト本文のバッファサイズ。本文がこれを超えると、一時ファイルに書き込まれます。
  • client_header_buffer_size: クライアントリクエストの最初の行とヘッダーのバッファサイズ。
  • large_client_header_buffers: クライアントリクエストヘッダーを読み取るための大きなバッファの数とサイズを定義します。多くのCookieや長いリファラーヘッダーを持つリクエストに便利です。

プロキシバッファ(リバースプロキシ設定の場合)

  • proxy_buffers: プロキシサーバーからの応答を読み取るために使用されるバッファの数とサイズ。
  • proxy_buffer_size: 応答を読み取るための最初のバッファのサイズ。通常は小さく、多くの場合ヘッダーのみが含まれます。
  • proxy_busy_buffers_size: 任意の時点で「ビジー」状態(クライアントに積極的に送信中)になる可能性のある応答バッファの最大量。

FastCGIバッファ(PHP-FPMなど用)

  • fastcgi_buffers: FastCGIサーバーからの応答を読み取るために使用されるバッファの数とサイズ。
  • fastcgi_buffer_size: 応答を読み取るための最初のバッファのサイズ。
http {
    # クライアントバッファ
    client_body_buffer_size 1M; # 想定されるリクエスト本文サイズ(例:ファイルアップロード)に基づいて調整
    client_header_buffer_size 1k;
    large_client_header_buffers 4 8k; # 4つのバッファ、各8KB

    # プロキシバッファ(Nginxがリバースプロキシとして機能する場合)
    proxy_buffers 8 16k; # 8つのバッファ、各16KB
    proxy_buffer_size 16k; # 最初のバッファ16KB
    proxy_busy_buffers_size 16k; # 最大16KBのビジーバッファ

    # FastCGIバッファ(NginxがPHP-FPMと連携する場合)
    fastcgi_buffers 16 16k; # 多くのPHP-FPMアプリの開始点
    fastcgi_buffer_size 16k; # 最初のバッファ16KB
}

警告: バッファを小さく設定しすぎると、ディスクI/Oとパフォーマンスの低下につながる可能性があります。大きく設定しすぎると、過剰なメモリを消費する可能性があります。テストを通じてバランスを見つけてください。

4. 堅牢なキャッシュ戦略の実装

キャッシュは、パフォーマンスを向上させ、バックエンドサーバーの負荷を軽減する最も効果的な方法の1つです。Nginxは強力なコンテンツキャッシュとして機能します。

proxy_cache_path

キャッシュディレクトリへのパス、そのサイズ、サブディレクトリレベルの数、および非アクティブなアイテムがキャッシュに残る期間を定義します。

proxy_cache

特定のlocationブロックのキャッシュをアクティブにし、proxy_cache_pathで定義されたゾーンを参照します。

proxy_cache_valid

Nginxが特定のHTTPステータスコードの応答をキャッシュする時間を設定します。

proxy_cache_revalidate

有効にすると、NginxはIf-Modified-SinceおよびIf-None-Matchヘッダーを使用してバックエンドでキャッシュされたコンテンツを再検証し、帯域幅の使用量を削減します。

proxy_cache_use_stale

バックエンドサーバーがダウンしている、応答しない、またはエラーが発生している場合に、Nginxが古いキャッシュコンテンツを提供するように指示します。これにより、可用性が大幅に向上します。

expires

静的ファイルのクライアント側キャッシュ用にCache-ControlおよびExpiresヘッダーを設定します。これにより、Nginxへの繰り返しリクエストが最小限に抑えられます。

http {
    # httpブロックでプロキシキャッシュゾーンを定義
    proxy_cache_path /var/cache/nginx/my_cache levels=1:2 keys_zone=my_cache:10m inactive=60m max_size=10g;

    server {
        listen 80;
        server_name example.com;

        location / {
            proxy_pass http://my_upstream_backend;
            proxy_cache my_cache; # このロケーションのキャッシュを有効化
            proxy_cache_valid 200 302 10m; # 成功応答を10分間キャッシュ
            proxy_cache_valid 404 1m; # 404を1分間キャッシュ
            proxy_cache_revalidate on;
            proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
            add_header X-Cache-Status $upstream_cache_status; # デバッグに役立つ
        }

        # ブラウザで静的ファイルをより長期間キャッシュ
        location ~* \.(jpg|jpeg|gif|png|css|js|ico|woff|woff2|ttf|svg|eot)$ {
            expires 30d; # 30日間キャッシュ
            add_header Cache-Control "public, no-transform";
            # 静的ファイルの場合、プロキシされていない場合はNginxから直接提供することを検討
            root /var/www/html;
        }
    }
}

5. Gzip圧縮の有効化

クライアントに送信する前に応答を圧縮すると、特にテキストベースのコンテンツの場合、帯域幅の使用量を大幅に削減し、ページの読み込み時間を改善できます。

gzip on

gzip圧縮を有効にします。

gzip_comp_level

圧縮レベル(1〜9)を設定します。レベル1は最も高速で圧縮率は低く、レベル9は最も低速で最大圧縮です。レベル6は通常、適切なバランスを提供します。

gzip_types

圧縮する必要があるMIMEタイプを指定します。一般的なテキスト、CSS、JavaScript、JSONタイプを含めます。

gzip_min_length

圧縮を有効にする応答の最小長(バイト単位)を設定します。小さなファイルはあまりメリットがなく、圧縮のオーバーヘッドにより遅くなる可能性さえあります。

gzip_proxied

応答がプロキシされている場合でもNginxに圧縮するよう指示します。anyは一般的な値です。

gzip_vary

応答にVary: Accept-Encodingヘッダーを追加し、応答がAccept-Encodingリクエストヘッダーに基づいて異なる可能性があることをプロキシに通知します。

http {
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6; # 圧縮レベル1〜9(6は適切なバランス)
    gzip_buffers 16 8k; # 16バッファ、各8KB
    gzip_http_version 1.1; # 圧縮の最小HTTPバージョン
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;
    gzip_min_length 1000; # 1KBより大きい応答のみを圧縮
}

6. ロギングの最適化

ログは監視とトラブルシューティングに不可欠ですが、過剰または最適化されていないロギングは、特に高トラフィックサイトでは、重大なディスクI/Oを引き起こす可能性があります。

access_log

  • 静的アセットでは無効にする: アクセス頻度の高い静的コンテンツ(画像、CSS、JS)の場合、access_logを無効にすると、多くのI/Oを節約できます。
  • バッファリング: Nginxは、ディスクに書き込む前にログエントリをメモリにバッファリングできるため、ディスク書き込みの頻度が減ります。ここではbufferおよびflushパラメータが使用されます。

error_log

適切なログレベル(criterrorwarninfodebug)を設定します。本番環境では、warnまたはerrorで通常、重大な問題をキャプチャするのに十分であり、ログが溢れることはありません。

http {
    server {
        # 動的コンテンツのデフォルトアクセスログ
        access_log /var/log/nginx/access.log main;

        location ~* \.(jpg|jpeg|gif|png|css|js|ico|woff|woff2|ttf|svg|eot)$ {
            access_log off; # 一般的な静的ファイルのロギングを無効化
            expires 30d;
        }
    }

    # メインHTTPコンテキストのバッファリングされたアクセスログの例
    # access_log /var/log/nginx/access.log main buffer=16k flush=5s;
    error_log /var/log/nginx/error.log warn; # 警告以上のみをログに記録
}

7. タイムアウトの調整

適切に設定されたタイムアウトは、Nginxが非アクティブな接続を長時間保持するのを防ぎ、リソースを解放します。

クライアント側タイムアウト

  • client_body_timeout: Nginxがクライアントからのリクエスト本文の送信を待機する時間。
  • client_header_timeout: Nginxがクライアントからのリクエストヘッダーの送信を待機する時間。
  • send_timeout: Nginxが応答を送信した後、クライアントがそれを受け入れるのを待機する時間。

プロキシ/FastCGIタイムアウト(該当する場合)

  • proxy_connect_timeout: プロキシサーバーとの接続を確立するためのタイムアウト。
  • proxy_send_timeout: プロキシサーバーにリクエストを送信するためのタイムアウト。
  • proxy_read_timeout: プロキシサーバーから応答を読み取るためのタイムアウト。
http {
    client_body_timeout 15s; # クライアントは本文を送信するために15秒
    client_header_timeout 15s; # クライアントはヘッダーを送信するために15秒
    send_timeout 15s; # Nginxはクライアントに応答を送信するために15秒

    # プロキシシナリオの場合
    proxy_connect_timeout 5s; # アップストリームに接続するために5秒
    proxy_send_timeout 15s; # アップストリームにリクエストを送信するために15秒
    proxy_read_timeout 15s; # アップストリームから応答を読み取るために15秒

    # FastCGIシナリオの場合
    fastcgi_connect_timeout 5s;
    fastcgi_send_timeout 15s;
    fastcgi_read_timeout 15s;
}

8. SSL/TLSの最適化

HTTPS対応サイトの場合、SSL/TLS設定の最適化は、CPUオーバーヘッドを削減し、ハンドシェイクパフォーマンスを向上させるために重要です。

ssl_session_cachessl_session_timeout

SSLセッションキャッシュを有効にして、同じクライアントからの後続の接続に対して計算コストの高い完全なTLSハンドシェイクを回避します。

ssl_protocolsssl_ciphers

TLSv1.2TLSv1.3などの最新のTLSプロトコルを使用します。コピーされた暗号スイート文字列には注意してください。TLS 1.3暗号は古いTLS暗号スイートと同じように制御されず、ディストリビューションのデフォルトは古いガイドの古い例よりも安全であることがよくあります。

ssl_stapling

OCSPステープリングを有効にします。これにより、NginxはCAから定期的にOCSP応答をフェッチし、それをSSL/TLSハンドシェイクに「ステープル」します。これにより、個別のOCSPクエリが不要になり、クライアント側のレイテンシが削減されます。

server {
    listen 443 ssl;
    ssl_certificate /etc/nginx/ssl/your_domain.crt;
    ssl_certificate_key /etc/nginx/ssl/your_domain.key;

    ssl_session_cache shared:SSL:10m; # 10MBのセッションデータ用の共有キャッシュ
    ssl_session_timeout 10m; # セッションは10分後に期限切れ

    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:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305';
    ssl_prefer_server_ciphers on;

    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 1.1.1.1 8.8.8.8 valid=300s; # 環境に承認されたリゾルバーを使用
    resolver_timeout 5s;
}

9. オープンファイルキャッシュ

Nginxは頻繁にアクセスされるファイルのファイル記述子をキャッシュできるため、ファイルを開いたり閉じたりするための繰り返しのシステムコールが削減されます。

open_file_cache

キャッシュを有効にし、最大要素数と非アクティブな要素が残る時間を指定します。

open_file_cache_valid

キャッシュがその要素の有効性をチェックする頻度を設定します。

open_file_cache_min_uses

inactive時間内にファイルにアクセスする必要がある最小回数を指定して、キャッシュに残します。

open_file_cache_errors

ファイルを開くときにNginxがエラーをキャッシュするかどうかを決定します。

http {
    open_file_cache max=100000 inactive=60s; # 最大100,000のファイル記述子を60秒間キャッシュ
    open_file_cache_valid 80s; # 80秒ごとに有効性をチェック
    open_file_cache_min_uses 1; # 少なくとも1回使用されたファイルをキャッシュ
    open_file_cache_errors on; # ファイルオープンに関連するエラーをキャッシュ
}

10. 実際のトラフィックシグナルで検証する

チェックリストの最後の項目は測定です。変更を行う前に、リクエストレイテンシ、5xxレート、アクティブ接続数、CPU、メモリ、ディスクI/O、ネットワークスループット、アップストリーム応答時間など、小さなベースラインを取得します。変更後、同じ数値を比較します。

リバースプロキシの場合、$request_time$upstream_response_timeは特に便利です。両方が一緒に上昇する場合、バックエンドが遅い可能性があります。$request_timeが高いのにアップストリーム時間が低いか空の場合は、クライアントのアップロード速度、応答転送時間、バッファリング、圧縮、または静的ファイル配信を確認してください。どちらのメトリクスも問題を説明しない場合は、エラーログとオペレーティングシステムを確認してください。

最も安全なチューニング手順は単純です。nginx -tで設定をテストし、可能な場合は再起動ではなくリロードを使用し、ログを監視し、レイテンシやエラーが悪化した場合はすぐにロールバックします。Nginxは多くのトラフィックを処理できますが、それはその制限、カーネル、およびアップストリームアプリケーションが相互に一致している場合に限ります。