Nginxのパフォーマンス最適化:ウェブサイトを高速化するためのヒント

包括的なパフォーマンス最適化ガイドで、Nginxサーバーの可能性を最大限に引き出しましょう。ワーカープロセス(worker processes)の微調整、強固なキャッシュ戦略の実装、効率的な圧縮(Gzip/Brotli)の有効化、および接続処理の最適化について学びます。この記事では、実用的なNginx構成のヒントとベストプラクティスを提供し、ロード時間の劇的な短縮、ユーザーエクスペリエンスの向上、ウェブサイト全体の速度と効率の向上を実現します。ピークパフォーマンスを追求するシステム管理者およびウェブ開発者にとって必読です。

Nginxパフォーマンス最適化:ウェブサイトを高速化するためのヒント

遅いサイトは、通常、いくつかの原因から発生します:高コストなアップストリーム応答、キャッシュヘッダーの欠如、過大なアセット、ブロックされたワーカー、またはトラフィックではなくデフォルト設定に調整されたサーバーです。Nginxのパフォーマンス最適化は、まず測定し、一度に1つの設定を変更し、設定を読みやすく保つことで最も効果を発揮します。

以下の例を出発点として使用し、実際のアプリに対してロードテストを行ってください。静的ファイルサーバー、WordPress/PHP-FPMサイト、APIリバースプロキシでは、異なるトレードオフが必要です。

Nginxパフォーマンスのボトルネックを理解する

まずボトルネックを見つけましょう。一般的な原因は以下の通りです:

  • CPU使用率: CPU負荷が高いと、リクエスト処理、圧縮、TLS処理が遅くなります。
  • メモリプレッシャー: スワッピングはレイテンシに大きな悪影響を及ぼします。
  • ネットワークI/O: 低速なリンク、小さなアップストリームウィンドウ、パケットロスが応答時間を支配することがあります。
  • ディスクI/O: 静的ファイル、キャッシュファイル、ログは依然としてストレージにアクセスします。
  • アップストリームレイテンシ: Nginxが高速でも、アプリサーバーが遅い場合があります。

tophtopiostatss、アクセスログ、Nginxのstub_statusモジュールなどのツールを使用して、何を調整すべきかを判断できます。

コアNginx最適化テクニック

ワーカープロセスと接続

worker_processesディレクティブは、Nginxが起動するワーカープロセスの数を制御します。autoは実用的なデフォルトであり、Nginxが利用可能なCPUコアを検出します。

# worker_processesをCPUコア数に設定
worker_processes auto;

各ワーカープロセス内で、worker_connectionsはそのワーカーが開くことができる同時接続数を制限します。おおよその上限はworker_processes * worker_connectionsですが、実際の容量はアップストリーム接続、オープンファイル制限、キープアライブ動作、オペレーティングシステムの制限にも依存します。

# 高トラフィックサイト向けにworker_connectionsを増加
worker_connections 1024;

Too many open filesが表示される場合、worker_connectionsだけを増やしても不十分です。サービスのファイルディスクリプタ制限も確認してください。これは多くの場合、systemdのLimitNOFILEやシェルの制限で制御されます。

キャッシュ戦略

キャッシュは通常、最も効果の高いNginxパフォーマンス最適化です。なぜなら、繰り返しの作業を防ぐからです。

ブラウザキャッシュ

画像、CSS、JavaScriptなどのバージョン管理された静的アセットをブラウザにキャッシュするように指示します。ファイル名がデプロイ時に変更される場合(例:app.8f3c1.css)にのみ、長い有効期間を使用します。

location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
    expires 30d;
    add_header Cache-Control "public";
}

プロキシキャッシュ

Nginxがリバースプロキシの場合、選択したバックエンド応答をキャッシュできます。これは、公開ページ、明確な鮮度ルールを持つAPI応答、ユーザーごとに変化しない高コストなページに適しています。

まず、httpブロックでキャッシュゾーンを定義します:

http {
    # ... その他のhttp設定 ...
    proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60m;
    # ...
}
  • /var/cache/nginx:キャッシュファイルが保存されるディレクトリ。
  • levels=1:2:キャッシュのディレクトリ構造を定義します。
  • keys_zone=my_cache:10m:キャッシュキーを保存するために、my_cacheという名前の共有メモリゾーンを10MBで作成します。
  • max_size=1g:キャッシュの最大サイズを設定します。
  • inactive=60m:60分間アクセスされていないキャッシュエントリを削除します。

次に、locationブロックでキャッシュを有効にします:

location / {
    proxy_pass http://your_backend_app;
    proxy_cache my_cache;
    proxy_cache_valid 200 302 10m; # 200および302応答を10分間キャッシュ
    proxy_cache_valid 404 1m;     # 404応答を1分間キャッシュ
    add_header X-Cache-Status $upstream_cache_status;
}

add_header X-Cache-Status $upstream_cache_status;はデバッグに便利で、リクエストがキャッシュヒット、ミス、またはバイパスされたかを示します。

キャッシュキーが応答を変更するデータを考慮しない限り、パーソナライズされたページはキャッシュしないでください。例えば、ログインしたダッシュボードは通常プロキシキャッシュをバイパスするべきですが、/assets/logo.pngは長期間キャッシュできます。

圧縮

圧縮は、HTML、CSS、JavaScript、JSON、XMLなどのテキストベースの応答の転送サイズを削減します。JPEG、PNG、MP4、多くのアーカイブ形式など、すでに圧縮されたファイルにはあまり効果がありません。

http {
    # ...
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
    # ...
}
  • gzip on;:Gzip圧縮を有効にします。
  • gzip_vary on;Vary: Accept-Encodingヘッダーを追加します。これはキャッシュプロキシにとって重要です。
  • gzip_proxied any;:プロキシされたリクエストの応答も圧縮します。
  • gzip_comp_level 6;:圧縮レベルを設定します(1-9、高いほど圧縮率は高いがCPU負荷も高い)。
  • gzip_types ...;:圧縮するMIMEタイプを指定します。

Brotliはテキストアセットをうまく圧縮できますが、標準のオープンソースNginxビルドにはすべてBrotliサポートが含まれているわけではありません。Brotliディレクティブを追加する前に、パッケージまたはモジュールセットを確認してください。

接続処理とキープアライブ

keepalive_timeoutディレクティブは、アイドル状態のクライアント接続が開いたままになる時間を制御します。接続を再利用すると、余分なTCPおよびTLSハンドシェイクを回避できますが、アイドル接続はリソースを消費します。

http {
    # ...
    keepalive_timeout 65;
    keepalive_requests 1000;
    # ...
}
  • keepalive_timeout 65;:キープアライブタイムアウトを65秒に設定します。
  • keepalive_requests 1000;:単一のキープアライブ接続で行える最大リクエスト数を設定します。

短いリクエストが多いAPIでは、キープアライブが役立ちます。アイドルクライアントが多い小規模サーバーでは、より短いタイムアウトが適している場合があります。

バッファリングとリクエストサイズ制限

Nginxは、クライアントボディとプロキシ応答にバッファを使用します。デフォルトは多くのサイトで問題ありませんが、アップロードが多いアプリや大きなアップストリームヘッダーでは、明示的な設定が必要になる場合があります。

http {
    # ...
    client_body_buffer_size 10K;
    client_max_body_size 8M;
    proxy_buffers 8 16k;
    proxy_buffer_size 16k;
    proxy_connect_timeout 60;
    proxy_send_timeout 60;
    proxy_read_timeout 60;
    # ...
}
  • client_body_buffer_size:クライアントリクエストボディの読み取りに使用されるバッファのサイズ。
  • client_max_body_size:クライアントリクエストボディの最大許容サイズ。
  • proxy_buffersproxy_buffer_size:Nginxがプロキシとして動作する際のバッファリングを制御します。

バッファスニペットを盲目的にコピーしないでください。upstream sent too big headerが表示された場合は、proxy_buffer_sizeを上げる前にアップストリームヘッダーを調査してください。アップロードが413 Request Entity Too Largeで失敗する場合は、client_max_body_sizeをアプリが実際にサポートするサイズに設定してください。

TLS最適化

HTTPSサイトの場合、TLS設定はレイテンシとセキュリティの両方に影響します。

  • セッション再開: セッションキャッシュを使用して、繰り返しの接続を高速化します。
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_session_tickets off;
    
  • TLSバージョン: 互換性要件で特に指定がない限り、TLS 1.2とTLS 1.3を有効にします。
  • OCSPステープリング: 証明書チェーンがサポートしている場合、証明書検証のラウンドトリップを削減できます。
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    

静的ファイルの提供

Nginxは静的ファイルの提供に優れています。これらのディレクティブはhttpブロックで一般的です:

  • sendfile サポートされているシステムで、カーネルがファイルデータをソケットに直接コピーできるようにします。
    sendfile on;
    
  • tcp_nopushtcp_nodelay 一般的なHTTPワークロード向けにパケット送信動作を調整します。
    tcp_nopush on;
    tcp_nodelay on;
    

監視とテスト

各変更後、テストして比較してください。便利なツールは以下の通りです:

  • Nginx stub_status アクティブ接続、受け入れられた接続、処理された接続、リクエスト。
  • top/htop CPUとメモリのプレッシャー。
  • iostat ディスクI/O。
  • WebPageTestまたはPageSpeed Insights: ブラウザ側のパフォーマンス。
  • wrkab、またはhey 制御されたエンドポイントに対するローカルロードテスト。

以前の設定のコピーを保持し、sudo nginx -tを実行し、リロードして、レイテンシ、エラー率、CPU、アップストリーム応答時間を比較してください。最良のNginxパフォーマンス最適化とは、測定によって証明できるものです。

実践的なポイント

測定から始め、最初に最大のボトルネックを修正してください。ほとんどのウェブサイトでは、適切なワーカー制限の設定、静的アセットへのブラウザキャッシュの追加、gzipの有効化、安全なアップストリーム応答のキャッシュ、そしてリロードごとにログを監視することを意味します。