Nginxによる基本キャッシュ:応答時間の改善

キャッシュゾーン、TTL、バイパスルール、ステータスヘッダー、テスト手順を用いて、Nginxプロキシキャッシュを安全に設定します。

Nginxによる基本キャッシュ:応答時間の改善

Nginxによる基本キャッシュは、アップストリームの応答のコピーを保存し、毎回アプリケーションに問い合わせることなく再提供することで、応答時間を改善できます。注意深く使用すれば、キャッシュはバックエンドの負荷を軽減し、トラフィックの急増を平滑化し、繰り返しのリクエストを高速化します。

キャッシュは大規模サイトだけのものではありません。ページやAPI応答、静的ファイルが頻繁にリクエストされ、毎秒変化しない場合、小規模なアプリでも恩恵を受けられます。

Nginxがキャッシュできるもの

Nginxはリバースプロキシとして動作する際に、アップストリームサーバーからの応答をキャッシュできます。これは通常のブラウザキャッシュとは異なります。ブラウザキャッシュはユーザーのデバイスにファイルを保存します。Nginxプロキシキャッシュはサーバーに応答を保存するため、多くのユーザーが同じキャッシュコピーの恩恵を受けられます。

シンプルなプロキシキャッシュ設定は2つの部分からなります。まず、httpブロック内でキャッシュゾーンを定義します:

proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=app_cache:10m
    max_size=1g inactive=60m use_temp_path=off;

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

location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_cache app_cache;
    proxy_cache_valid 200 10m;
    proxy_cache_valid 404 1m;
    add_header X-Cache-Status $upstream_cache_status;
}

proxy_cache_pathディレクティブはキャッシュストレージ領域を作成します。keys_zoneはキャッシュキーとメタデータ用の共有メモリを定義します。max_sizeはディスク使用量を制限します。inactiveはしばらくアクセスされていないアイテムを削除します。

proxy_cache_validディレクティブは、特定の応答コードがキャッシュされる期間を決定します。この例では、成功応答は10分間キャッシュされ、404応答は1分間キャッシュされます。

X-Cache-Statusヘッダーはテスト中に便利です。状況に応じてMISSHITBYPASSEXPIREDなどの値を表示できます。

Nginxをリバースプロキシとしても使用するサイトでは、これはリバースプロキシ設定と自然に組み合わさります。

何をキャッシュすべきか判断する

Nginxキャッシュの最も難しい部分は、ディレクティブを書くことではありません。再利用しても安全なコンテンツを判断することです。

キャッシュに適した候補:

  • 公開マーケティングページ。
  • 公開ドキュメントページ。
  • 予測可能なスケジュールで更新される商品一覧ページ。
  • 匿名API応答。
  • 多くのユーザーに対して同一の、高コストなアップストリーム応答。

キャッシュに適さない候補:

  • アカウントページ。
  • ショッピングカート。
  • 管理画面。
  • プライベートユーザーデータを含む応答。
  • クッキーや認証ヘッダーに基づいて変化するページ。

応答がユーザーごとに異なる場合、非常に明確なキャッシュキー戦略がない限りキャッシュしないでください。誤ってあるユーザーのプライベート応答を別のユーザーに提供することは重大なバグです。

リクエストにセッションや認証データが含まれる場合、キャッシュをバイパスできます:

proxy_cache_bypass $http_authorization;
proxy_no_cache $http_authorization;

クッキーベースのセッションの場合、同様のパターンを使用できます:

proxy_cache_bypass $cookie_session;
proxy_no_cache $cookie_session;

正確なクッキー名はアプリケーションに依存します。アプリがセッションをどのように処理するか確認せずに、盲目的にコピーしないでください。

実用的なシナリオ:公開ブログのホームページがアプリケーションによって生成され、忙しい日に300ミリ秒かかるとします。そのページを5分間キャッシュすれば、ほとんどの訪問者はキャッシュされたコピーを素早く受け取り、アプリはたまにしか再生成しません。ホームページは公開されておりユーザー固有ではないため、これは強力なユースケースです。

キャッシュキー、ヘッダー、パージ

Nginxはキャッシュキーを使用して、2つのリクエストが同じキャッシュ応答を共有すべきか判断します。デフォルトのキャッシュキーは通常、スキーム、メソッド、ホスト、URIに基づいています。多くのサイトではこれで十分です。

クエリ文字列が応答を変更する場合、それらがキーの一部であることを確認してください。クエリ文字列が単なるトラッキングパラメータである場合、すべてのutm_sourceが個別のキャッシュエントリを作成するのではなく、アプリケーションまたはCDN層で正規化することを検討してください。

アップストリームのキャッシュヘッダーも重要です。アプリは次のようなヘッダーを送信できます:

Cache-Control: public, max-age=600

または:

Cache-Control: private, no-store

Nginxはこれらのヘッダーを尊重または上書きするように設定できますが、明確なポリシーを1つ選択する必要があります。アプリ開発者がCache-Control: no-storeでキャッシュを防止することを期待している場合、Nginxでその動作を上書きすると、混乱を招きリスクのある結果を生む可能性があります。

パージも運用上の問題です。オープンソースのNginxには、一部の商用またはサードパーティモジュールのように、シンプルな組み込みのキャッシュパージエンドポイントは含まれていません。多くのチームは、短いキャッシュ期間、バージョン付きURL、または管理されたリリース中にキャッシュディレクトリをクリアするデプロイスクリプトを使用してこれを処理します。

短いTTLで十分なことがよくあります。ビジーなエンドポイントで60秒のキャッシュでも、コンテンツを適度に新鮮に保ちながら、大量のバックエンドトラフィックを削減できます。

キャッシュ動作のテスト

キャッシュを有効にした後、同じURLに数回リクエストし、応答ヘッダーを確認します:

curl -I https://example.com/

X-Cache-Statusを追加した場合、最初のリクエストはMISSを示し、後のリクエストはHITを示すはずです。すべてのリクエストがMISSの場合、応答ヘッダー、キャッシュバイパスルール、リクエストクッキー、およびキャッシュディレクトリがNginxワーカープロセスによって書き込み可能かどうかを確認してください。

また、ログイン時とログアウト時の動作をテストしてください。ここで多くのキャッシュミスが発生します。プライベートブラウザウィンドウを開き、テストユーザーとしてサインインし、プライベートページが公開キャッシュされていないことを確認します。

ディスク使用量も監視してください。実質的な制限のないキャッシュはファイルシステムを満たす可能性があります。max_sizeを使用し、可能であればキャッシュストレージを重要なシステムパーティションから分離し、ディスクプレッシャーに関するアラートを設定してください。

助けを求めるタイミング

キャッシュされたコンテンツが誤ったユーザーの下に表示される場合、チューニング後もキャッシュヒット率が低いままの場合、またはキャッシュファイルが予期せずディスクを満たしている場合は、経験豊富なNginxまたはプラットフォームエンジニアを呼んでください。キャッシュの問題は単純に見えても、アプリケーション固有の動作を隠していることがあります。

また、認証されたAPI、マルチテナントダッシュボード、または支払い関連のフローをキャッシュする前には助けを求めるべきです。これらの領域は慎重な設計が必要です。

Nginxによる基本キャッシュは、公開され繰り返し可能な応答と短いキャッシュ期間から始めるのが最適です。テスト中は可視のキャッシュステータスヘッダーを追加し、プライベートコンテンツの境界を尊重し、応答時間とバックエンド負荷の両方を測定してください。適切に行えば、キャッシュはユーザーに高速なページを提供し、アプリケーションに余裕をもたらします。