本記事では、CDNで利用されるキャッシュキー(Cache Key)について解説します。 キャッシュキーはCDNにおいて最も重要な概念と言っても過言ではありません。
キャッシュキーの設定を適切に行うことで、キャッシュの効率を改善したり、ユーザーの端末に応じてコンテンツを出し分けた時にキャッシュが混ざらないようにすることができます。
まずはキャッシュキーの説明に入る前にCDNのキャッシュがどのように行われるかを確認しましょう。
CDNのキャッシュの動作をおさらい
しばらくDNSとHTTPの基礎のお話をしてきたので、一度ここでCDNのキャッシュがどのような動作だったかをおさらいします。
最初の状態では、オリジンサーバーのみがコンテンツ/index.html
を持っています。
ユーザーはこのコンテンツを取得するためのGETリクエストをエッジサーバーに送信します。エッジサーバーはこのコンテンツのキャッシュを持っていないため、オリジンサーバーにリクエストを転送します。
次に、エッジサーバーは、オリジンサーバーから受け取った /index.html
をキャッシュしつつユーザーに返送します。
同じコンテンツが再度リクエストされた場合は、エッジサーバーにあるキャッシュを使用するため、オリジンサーバーへはリクエストが飛ばず、レスポンスが高速化されます。
ここまでは第1回で説明した通りです。実はこの説明には曖昧さがあります。「同じコンテンツ」は何をもって同じと言えるのでしょうか? なんとなく /index.html
とリクエストするコンテンツのURLパスが同じであれば同じコンテンツとして扱って良いような気がします。
実際は、多くの場合はこれで問題ありません。 ただし、ここには/index.html
の内容が誰に対しても同じであるという前提があります。
では、この前提が成り立たないのはどんな時でしょうか? 例えば、次のようなサイトでは/index.html
は見るユーザーによって変わってきます。
- ユーザーのブラウザの言語設定に応じてページの言語を変えている
- PCとスマートフォン向けで表示するコンテンツを変えている
これらのケースでは、最初にアクセスしたユーザーの設定に対したコンテンツが全ユーザーに配信されてしまいます。つまり、最初にアクセスしたユーザーがPCであれば、エッジサーバーにはPC用の/index.html
がキャッシュされているため、次のユーザーがスマートフォンであってもPC用のコンテンツが返ってきてしまいます。
これを解決するのがキャッシュキー(Cache Key)と呼ばれる概念です。
キャッシュキー(Cache Key)とは
キャッシュキーは、CDNにて同一のコンテンツであると判断するために使われる識別子です。
一般的に次の要素をキャッシュキーに含めることができます。
- URLパス(必須)
- HTTPリクエストヘッダー
- クエリ文字列
- Cookie
クエリ文字列は、これまで触れてこなかったのでここで解説します。
クエリ文字列は、次のようなURLのクエスチョンマーク(?)以降の文字列のことを指します。 下記の例では、商品の情報を見る/get_item.php
にどの商品の注文かを示す item_id
というクエリ文字列を追加しています。
/get_item.php?item_id=1
/get_item.php?item_id=2
このケースでは、URLパスとクエリ文字列 item_id
をキャッシュキーに含めることでキャッシュを分けることができます。
また、先ほどの例の「PCとスマートフォン向けで表示するコンテンツを変えている」場合であれば、HTTPヘッダーのUser-Agent
をキャッシュキーに入れることでPCとスマートフォンに対して異なるキャッシュを使えます。
ただし、この解決策では、キャッシュがほとんど利用されなくなってしまうという落とし穴があります。
次のセクションで、User-Agent
をキャッシュキーに入れるべきではない理由とその解決策について解説します。
キャッシュキーを適切にしないとキャッシュ効率が落ちる
Mac OSのGoogle Chromeを使った際のUser-Agentを例として見てみます。User-Agentによって端末がPCなのかスマートフォンなのかはもちろん、ユーザが使っているOSやブラウザとそのバージョンまで識別することができます。
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
では、なぜUser-Agent
をキャッシュキーに入れるべきではないのでしょうか?
User-Agent
には、ブラウザのバージョンが含まれていることが一番大きな問題です。
上記の例だと、Chromeのバージョン 120を使用していますが、Chromeのバージョン 119のユーザーにも同じコンテンツを見せたいはずです。にも関わらず、キャッシュキーにUser-Agent
が含まれているとブラウザのバージョンごとに違うコンテンツとして扱われてしまうため、キャッシュがほとんど利用されません。
このケースの解決方法は、CDN事業者から提供されています。
Amazon CloudFrontの場合は、CloudFront-Is-Desktop-Viewer
やCloudFront-Is-Mobile-Viewer
といったヘッダーをCloudFront側がユーザーのリクエストに追加するため、これらのヘッダーをキャッシュキーに含めることでPCとスマートフォンの識別を行うことができます。
キャッシュキーの設定のコツ
ここまでキャッシュキーの設定の重要性を具体例を交えて説明してきました。
URLパス以外の追加情報によって、コンテンツを出し分けする場合にはキャッシュキーの適切な設定が必要なことがお分かり頂けたかとと思います。ここでキャッシュキー設定のコツについてまとめます。
まず最初に考えるのは、そのコンテンツはユーザーの特性に応じて出し分けする必要があるか?です。出し分けが必要なければ、キャッシュキーの設定は不要です。通常通り、URLパスによってキャッシュが識別されます。
出し分けが必要な場合は、識別に使える要素を確認し、キャッシュキーに追加します。 この時、必要以上にキャッシューに追加しないこととUser-Agent
のようにパターンの多い要素であれば他の要素で代用できないか調査することをおすすめします。
Varyヘッダー
CDNでは、キャッシュキーによって、URLパスが同じコンテンツでもキャッシュを別にすることができました。では、ブラウザキャッシュではどうでしょうか?
ブラウザでも使える方法として、Vary
というHTTPレスポンスに追加されるヘッダーがあります。
Vary
ヘッダーは、キャッシュする際に考慮すべきリクエストヘッダーを指定します。例えば、Vary: Accept-Language
がレスポンスヘッダーに付与されることでブラウザの言語設定ごとにキャッシュを別にすることができます。
まとめ
本記事では、CDNにおけるキャッシュキー(Cache Key)の重要性について解説をしました。
キャッシュキーの適切な設定は次の2つの観点から重要でした。
- コンテンツの適切な出し分けることができる
- キャッシュの利用効率を高めることができる
次回はブラウザとCDN両方を含めたキャッシュ戦略について解説します。
CDN入門の記事一覧ページはこちらです。