ブログ | NGINX

NGINX と NGINX Plus を使用したキャッシュのガイド

NGINX-F5 水平黒タイプ RGB の一部
ファイサル・メモン サムネイル
ファイサル・メモン
2015 年 7 月 23 日公開

アプリケーションや Web サイトのパフォーマンスが成功の重要な要素であることは誰もが知っています。 ただし、アプリケーションや Web サイトのパフォーマンスを向上させるプロセスは必ずしも明確ではありません。 コードの品質とインフラストラクチャはもちろん重要ですが、多くの場合、いくつかの非常に基本的なアプリケーション配信テクニックに重点を置くことで、アプリケーションのエンドユーザー エクスペリエンスを大幅に改善できます。 そのような例の 1 つは、アプリケーション スタックにキャッシュを実装して最適化することです。 このブログ記事では、NGINX と NGINX Plus に含まれるコンテンツ キャッシュ機能を活用して、初心者と上級ユーザーの両方がパフォーマンスを向上させるのに役立つテクニックについて説明します。

概要

コンテンツ キャッシュは、クライアントと「オリジン サーバー」の間に配置され、認識したすべてのコンテンツのコピーを保存します。 クライアントがキャッシュに保存されているコンテンツを要求した場合、オリジン サーバーに接続せずにコンテンツを直接返します。 これにより、コンテンツ キャッシュがクライアントに近くなるためパフォーマンスが向上し、毎回ページを最初から生成する作業を行う必要がなくなるため、アプリケーション サーバーがより効率的に使用されます。

Web ブラウザーとアプリケーション サーバーの間には、クライアントのブラウザー キャッシュ、中間キャッシュ、コンテンツ配信ネットワーク (CDN)、アプリケーション サーバーの前にあるロード バランサーまたはリバース プロキシなど、複数のキャッシュが存在する可能性があります。 リバース プロキシ/ロード バランサー レベルでもキャッシュを使用すると、パフォーマンスが大幅に向上します。

たとえば、昨年私は、読み込みが遅い Web サイトのパフォーマンスを調整するという作業を引き受けました。 最初に気付いたことの 1 つは、メインのホームページを生成するのに 1 秒以上かかるということでした。 デバッグを行った結果、ページがキャッシュ不可としてマークされていたため、各リクエストに応じて動的に生成されていたことがわかりました。 ページ自体はあまり頻繁に変更されず、パーソナライズもされていなかったため、これは必要ありませんでした。 実験として、ホームページをロードバランサーによって 5 秒間キャッシュするようにマークしたところ、それだけで目立った改善が見られました。 最初のバイトまでの時間は数ミリ秒に短縮され、ページの読み込みが目に見えて速くなりました。

NGINX は、通常、アプリケーション スタック内のリバース プロキシまたはロード バランサとして導入され、完全なキャッシュ機能セットを備えています。 次のセクションでは、NGINX を使用して基本的なキャッシュを構成する方法について説明します。

基本的なキャッシュの設定方法

基本的なキャッシュを有効にするには、 proxy_cache_pathproxy_cache の2 つのディレクティブだけが必要です。 proxy_cache_pathディレクティブはキャッシュのパスと構成を設定し、 proxy_cacheディレクティブはそれをアクティブにします。

proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path=off; server { # ... location / { proxy_cache my_cache; proxy_pass http://my_upstream; } }

proxy_cache_pathディレクティブのパラメータは、次の設定を定義します。

  • キャッシュのローカル ディスク ディレクトリは/path/to/cache/と呼ばれます。
  • levels は、 /path/to/cache/の下に 2 レベルのディレクトリ階層を設定します。 1 つのディレクトリに多数のファイルがあるとファイル アクセスが遅くなる可能性があるため、ほとんどの展開では 2 レベルのディレクトリ階層を推奨します。 levelsパラメータが含まれていない場合、NGINX はすべてのファイルを同じディレクトリに配置します。
  • keys_zone は、キャッシュ キーと使用タイマーなどのメタデータを格納するための共有メモリ ゾーンを設定します。 キーのコピーをメモリ内に保持することで、NGINX はディスクにアクセスすることなくリクエストがHITMISS かをすばやく判断できるため、チェックの速度が大幅に向上します。 1 MB のゾーンには約 8,000 個のキーのデータが保存できるため、例で構成された 10 MB のゾーンには約 80,000 個のキーのデータが保存できます。
  • max_size はキャッシュのサイズの上限を設定します (この例では 10 ギガバイト)。 これはオプションです。値を指定しないと、キャッシュが拡張され、使用可能なディスク領域がすべて使用されます。 キャッシュ サイズが制限に達すると、キャッシュ マネージャーと呼ばれるプロセスが最も最近使用されていないファイルを削除して、キャッシュ サイズを制限内に戻します。
  • inactive は、アイテムがアクセスされずにキャッシュ内に保持される期間を指定します。 この例では、60 分間要求されていないファイルは、有効期限が切れているかどうかに関係なく、キャッシュ マネージャー プロセスによってキャッシュから自動的に削除されます。 デフォルト値は10分( 10m )です。 非アクティブなコンテンツは期限切れのコンテンツとは異なります。 NGINX は、キャッシュ制御ヘッダー(たとえば、 Cache-Control:max-age=120 ) で定義されている期限切れのコンテンツを自動的に削除しません。 期限切れ(古い)コンテンツは、 inactiveで指定された時間アクセスされなかった場合にのみ削除されます。 期限切れのコンテンツにアクセスすると、NGINX はオリジン サーバーからそのコンテンツを更新し、非アクティブタイマーをリセットします。
  • NGINX はまず、キャッシュ用のファイルを一時ストレージ領域に書き込み、 use_temp_path=offディレクティブは、それらのファイルをキャッシュされる同じディレクトリに書き込むように NGINX に指示します。 ファイルシステム間でのデータの不要なコピーを避けるため、このパラメータをオフに設定することをお勧めします。use_temp_path、NGINX バージョン 1.7.10 およびNGINX Plus R6で導入されました。

最後に、 proxy_cacheディレクティブは、親ロケーションブロックの URL (例では/ ) に一致するすべてのコンテンツのキャッシュを有効にします。 また、 proxy_cacheディレクティブをサーバーブロックに含めることもできます。これは、独自のproxy_cacheディレクティブを持たないサーバーのすべてのロケーションブロックに適用されます。

オリジンがダウンしたときにキャッシュされたコンテンツを配信する

NGINXコンテンツ キャッシュの強力な機能は、オリジン サーバーから最新のコンテンツを取得できない場合に、キャッシュから古いコンテンツを配信するように NGINX を構成できることです。 これは、キャッシュされたリソースのすべてのオリジン サーバーがダウンしているか、一時的にビジー状態の場合に発生する可能性があります。 NGINX は、エラーをクライアントに中継するのではなく、キャッシュからファイルの古いバージョンを配信します。 これにより、NGINX がプロキシするサーバーにさらなるレベルのフォールト トレランスが提供され、サーバー障害やトラフィックの急増が発生した場合でも稼働時間が確保されます。 この機能を有効にするには、 proxy_cache_use_staleディレクティブを追加します。

場所 / { # ... proxy_cache_use_staleエラー タイムアウト http_500 http_502 http_503 http_504; }

このサンプル構成では、NGINX がオリジン サーバーからエラータイムアウト、または指定された5xxエラーのいずれかを受信し、要求されたファイルの古いバージョンがキャッシュ内にある場合、エラーをクライアントに中継するのではなく、古いファイルを配信します。

キャッシュの微調整とパフォーマンスの向上

NGINX には、キャッシュのパフォーマンスを微調整するためのオプション設定が豊富に用意されています。 以下に、それらのいくつかをアクティブにする例を示します。

proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path=off; server { # ... location / { proxy_cache my_cache; proxy_cache_revalidate on; proxy_cache_min_uses 3; proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; proxy_cache_background_update on; proxy_cache_lock on; proxy_pass http://my_upstream; } }

これらのディレクティブは、次の動作を構成します。

  • proxy_cache_revalidate は、オリジン サーバーからコンテンツを更新するときに条件付きGETリクエストを使用するように NGINX に指示します。 クライアントが、キャッシュ制御ヘッダーで定義されているようにキャッシュされているが期限切れになっているアイテムを要求した場合、NGINX は、オリジン サーバーに送信するGET要求のヘッダーにIf-Modified-Sinceフィールドを含めます。 これにより、NGINX が最初にファイルをキャッシュしたときにファイルに添付されたLast-Modifiedヘッダーに記録された時間以降に変更された場合にのみ、サーバーが完全なアイテムを送信するため、帯域幅が節約されます。
  • proxy_cache_min_uses は、 NGINX がアイテムをキャッシュする前にクライアントがアイテムを要求する回数を設定します。 これは、最も頻繁にアクセスされるアイテムのみがキャッシュに追加されることを保証するため、キャッシュが常にいっぱいになっている場合に便利です。 デフォルトでは、 proxy_cache_min_usesは 1 に設定されています。
  • proxy_cache_use_staleディレクティブの更新パラメータとproxy_cache_background_updateディレクティブの有効化を組み合わせると、クライアントが期限切れまたはオリジン サーバーから更新中のアイテムを要求したときに、NGINX に古いコンテンツを配信するように指示します。 すべての更新はバックグラウンドで実行されます。 更新されたファイルが完全にダウンロードされるまで、すべてのリクエストに対して古いファイルが返されます。
  • proxy_cache_lockを有効にすると、複数のクライアントがキャッシュ内に現在存在しないファイル ( MISS ) を要求した場合、それらの要求のうち最初のものだけがオリジン サーバーに許可されます。 残りのリクエストは、そのリクエストが満たされるまで待機し、その後キャッシュからファイルを取得します。 proxy_cache_lockが有効になっていない場合、キャッシュ ミスとなるすべてのリクエストは直接元のサーバーに送信されます。

複数のハードドライブにキャッシュを分割する

複数のハードドライブがある場合は、NGINX を使用してキャッシュをそれらの間で分割できます。 以下は、リクエスト URI に基づいてクライアントを 2 つのハード ドライブに均等に分割する例です。

proxy_cache_path /path/to/hdd1 levels=1:2 keys_zone=my_cache_hdd1:10m max_size=10g inactive=60m use_temp_path=off;
proxy_cache_path /path/to/hdd2 levels=1:2 keys_zone=my_cache_hdd2:10m
max_size=10g inactive=60m use_temp_path=off;

split_clients $request_uri $my_cache {
50% “my_cache_hdd1”;
50% “my_cache_hdd2”;
}

server {
# ...
location / {
proxy_cache $my_cache;
proxy_pass http://my_upstream;
}
}

2 つのproxy_cache_pathディレクティブは、2 つの異なるハード ドライブ上の 2 つのキャッシュ ( my_cache_hdd1my_cache_hdd2 ) を定義します。 split_clients構成ブロックは、リクエストの半分 ( 50% ) の結果をmy_cache_hdd1にキャッシュし、残りの半分をmy_cache_hdd2にキャッシュすることを指定します。 $request_uri変数 (リクエスト URI) に基づくハッシュによって、各リクエストに使用されるキャッシュが決定され、その結果、特定の URI に対するリクエストは常に同じキャッシュにキャッシュされます。

このアプローチは RAID ハード ドライブ セットアップの代替ではないことに注意してください。 ハード ドライブに障害が発生すると、障害が発生したハード ドライブに送信された要求に対して 500 応答コードがユーザーに表示されるなど、システムで予期しない動作が発生する可能性があります。 適切な RAID ハード ドライブ設定により、ハード ドライブの障害に対処できます。

よくある質問(FAQ)

このセクションでは、NGINX コンテンツ キャッシュに関するよくある質問に回答します。

NGINX キャッシュをインストルメント化できますか?

はい、 add_headerディレクティブを使用すれば可能です:

add_header X-Cache-Status $upstream_cache_status;

この例では、クライアントへの応答にX-Cache-Status HTTP ヘッダーを追加します。 $upstream_cache_statusに指定できる値は次のとおりです。

  • MISS – 応答がキャッシュ内に見つからなかったため、元のサーバーから取得されました。 応答はキャッシュされている可能性があります。
  • BYPASS – リクエストがproxy_cache_bypassディレクティブに一致したため、応答はキャッシュから提供されるのではなく、オリジン サーバーから取得されました (以下の「キャッシュに穴を開けることはできますか? 」を参照してください)。 応答はキャッシュされている可能性があります。
  • EXPIRED – キャッシュ内のエントリの有効期限が切れています。 応答には、元のサーバーからの最新のコンテンツが含まれます。
  • STALE – オリジン サーバーが正しく応答せず、 proxy_cache_use_staleが構成されているため、コンテンツは古くなっています。
  • 更新中– エントリは以前のリクエストに応じて現在更新中であり、 proxy_cache_use_stale 更新が設定されているため、コンテンツは古くなっています。
  • REVALIDATEDproxy_cache_revalidateディレクティブが有効になり、NGINX は現在キャッシュされたコンテンツがまだ有効であることを確認しました ( If-Modified-SinceまたはIf-None-Match )。
  • HIT – 応答には、キャッシュから直接取得した有効な最新のコンテンツが含まれます。

NGINX はどのようにして何かをキャッシュするかどうかを決定するのでしょうか?

NGINX は、オリジン サーバーに将来の日付と時刻を含むExpiresヘッダー、またはmax-ageディレクティブがゼロ以外の値に設定されたCache-Controlヘッダーが含まれている場合にのみ、応答をキャッシュします。

デフォルトでは、NGINX はCache-Controlヘッダー内の他のディレクティブを尊重します。つまり、ヘッダーにPrivateNo-Cache 、またはNo-Storeディレクティブが含まれている場合は、応答をキャッシュしません。 また、 Set-Cookieヘッダーを含む応答もキャッシュされません。 さらに、 GETおよびHEADリクエストへの応答のみをキャッシュします。 以下の回答で説明されているように、これらのデフォルトを上書きできます。

proxy_bufferingoffに設定されている場合、NGINX は応答をキャッシュしません。 デフォルトではオンになっています。

Cache-Controlヘッダーを無視できますか?

はい、 proxy_ignore_headersディレクティブを使用します。 たとえば、次の構成の場合:

場所 /images/ { proxy_cache my_cache; proxy_ignore_headers Cache-Control; proxy_cache_valid any 30m; # ... }

NGINX は、 /images/の下にあるすべてのもののCache-Controlヘッダーを無視します。 proxy_cache_validディレクティブは、キャッシュされたデータの有効期限を強制し、 Cache-Controlヘッダーを無視する場合に必要です。 NGINX は有効期限のないファイルをキャッシュしません。

NGINX はヘッダーにSet-Cookieを含むコンテンツをキャッシュできますか?

はい、前の回答で説明したように、 proxy_ignore_headersディレクティブを使用します。

NGINX はPOSTリクエストをキャッシュできますか?

はい、 proxy_cache_methodsディレクティブを使用すると可能です:

proxy_cache_methods GET HEAD POST;

この例では、 POSTリクエストのキャッシュを有効にします。

NGINX は動的コンテンツをキャッシュできますか?

はい、 Cache-Controlヘッダーで許可されている場合は可能です。 動的コンテンツを短期間でもキャッシュすると、元のサーバーとデータベースの負荷が軽減され、リクエストごとにページを再生成する必要がなくなるため、最初のバイトまでの時間が短縮されます。

キャッシュに穴を開けることはできますか?

はい、 proxy_cache_bypassディレクティブを使用すれば可能です:

場所 / { proxy_cache_bypass $cookie_nocache $arg_nocache; # ... }

このディレクティブは、NGINX が最初にキャッシュ内でコンテンツを検索するのではなく、すぐにオリジン サーバーからコンテンツを要求するリクエスト タイプを定義します。 これは、キャッシュに「穴を開ける」と呼ばれることもあります。 この例では、NGINX は、 nocacheクッキーまたは引数を持つリクエストに対してこれを実行します (例: http://www.example.com/?nocache=true ) 。 NGINX は、バイパスされない将来のリクエストに対して結果の応答をキャッシュすることができます。

NGINX はどのキャッシュ キーを使用しますか?

NGINX が生成するキーのデフォルトの形式は、次のNGINX 変数の MD5 ハッシュに似ています: $scheme$proxy_host$request_uri 。実際に使用されるアルゴリズムは少し複雑です。

proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path=off;

server {
# ...
location / {
proxy_cache my_cache;
proxy_pass http://my_upstream;
}
}

このサンプル構成では、 http://www.example.org/my_image.jpgのキャッシュ キーはmd5(“http://my_upstream:80/my_image.jpg”)として計算されます。

ハッシュ値では、実際のホスト名 ( www.example.com ) ではなく、 $proxy_host変数が使用されることに注意してください。 $proxy_host はproxy_passディレクティブで指定されたプロキシ サーバーの名前とポートとして定義されます。

キーの基礎として使用される変数 (またはその他の用語) を変更するには、 proxy_cache_keyディレクティブを使用します (次の質問も参照)。

キャッシュ キーの一部として Cookie を使用できますか?

はい、キャッシュ キーは任意の値に設定できます。たとえば、次のようになります。

proxy_cache_key $proxy_host$request_uri$cookie_jessionid;

この例では、 JSESSIONID Cookie の値をキャッシュ キーに組み込みます。 URI が同じだがJSESSIONID値が異なるアイテムは、一意のアイテムとして個別にキャッシュされます。

NGINX はETagヘッダーを使用しますか?

NGINX 1.7.3 およびNGINX Plus R5以降では、 ETagヘッダーはIf-None-Matchとともに完全にサポートされています。

NGINX はバイト範囲リクエストをどのように処理しますか?

ファイルがキャッシュ内で最新である場合、NGINX はバイト範囲要求を尊重し、アイテムの指定されたバイトのみをクライアントに提供します。 ファイルがキャッシュされていない場合、または古い場合、NGINX はオリジン サーバーからファイル全体をダウンロードします。 リクエストが 1 バイトの範囲に対するものである場合、NGINX はダウンロード ストリームでその範囲が検出されるとすぐにその範囲をクライアントに送信します。 リクエストで同じファイル内の複数のバイト範囲が指定されている場合、ダウンロードが完了すると、NGINX はファイル全体をクライアントに配信します。

ダウンロードが完了すると、NGINX はリソース全体をキャッシュに移動し、単一の範囲または複数の範囲を問わず、今後のすべてのバイト範囲リクエストがキャッシュからすぐに満たされるようにします。

NGINX がアップストリーム サーバーへのバイト範囲リクエストを尊重するには、アップストリームサーバーがバイト範囲リクエストをサポートしている必要があることに注意してください。

NGINX はキャッシュの消去をサポートしていますか?

NGINX Plus は、キャッシュされたファイルの選択的な消去をサポートしています。 これは、ファイルがオリジン サーバー上で更新されているが、NGINX Plus キャッシュ内ではまだ有効な場合 ( Cache-Control:max-ageがまだ有効であり、 proxy_cache_pathディレクティブのinactiveパラメータによって設定されたタイムアウトが期限切れになっていない場合) に役立ちます。 NGINX Plus のキャッシュ消去機能を使用すると、このファイルを簡単に削除できます。 詳細については、 「キャッシュからのコンテンツの消去」を参照してください。

NGINX はプラグマヘッダーをどのように処理しますか?

Pragma:no-cacheヘッダーは、すべての中間キャッシュをバイパスし、要求されたコンテンツの元のサーバーに直接アクセスするためにクライアントによって追加されます。 NGINX はデフォルトではPragmaヘッダーを尊重しませんが、次のproxy_cache_bypassディレクティブを使用してこの機能を設定できます。

場所 /images/ { proxy_cache my_cache; proxy_cache_bypass $http_pragma; # ... }

NGINX は、 Cache-Controlヘッダーのstale-while-revalidateおよびstale-if-error拡張をサポートしていますか?

はい、 NGINX Plus R12および NGINX 1.11.10 以降では可能です。 これらの拡張機能の機能:

  • Cache-Control HTTP ヘッダーのstale-while-revalidate拡張により、キャッシュされた応答が現在更新中の場合、古い応答を使用することが許可されます。
  • Cache-Control HTTP ヘッダーのstale-if-error拡張により、エラーが発生した場合に古いキャッシュされた応答を使用することが許可されます。

これらのヘッダーは、上記のproxy_cache_use_staleディレクティブよりも優先度が低くなります。

NGINX はVaryヘッダーをサポートしていますか?

はい、 NGINX Plus R5および NGINX 1.7.7 以降では可能です。 Varyヘッダーの概要は次のとおりです。

さらに読む

NGINX キャッシュをカスタマイズおよび調整する方法は他にもたくさんあります。 NGINX によるキャッシュについてさらに詳しく知りたい場合は、次のリソースをご覧ください。


「このブログ投稿には、入手できなくなった製品やサポートされなくなった製品が参照されている場合があります。 利用可能な F5 NGINX 製品およびソリューションに関する最新情報については、 NGINX 製品ファミリーをご覧ください。 NGINX は現在 F5 の一部です。 以前の NGINX.com リンクはすべて、F5.com の同様の NGINX コンテンツにリダイレクトされます。"