CloudFrontとブラウザのキャッシュ設定ヒント

2019年現在、webでコンテンツを提供する場合に、キャッシュを使うことが普及しつつあります。
ですが、キャッシュには様々なメリット・デメリットがあり、使い方を間違うとデメリットが大きくなってしまいます。
なので今回はCDN(CloudFront)とブラウザそれぞれのキャッシュ設定について、考えることの基本をなるべく短くまとめました。

「キャッシュの設定をしたことがなく、今から始めようと思う」という方を読者として想定しています。

前提

ここで説明する設定の前提となる構成は、以下の図の通りです。(なるべく簡素に書いています)

構成図
構成図

コンテンツはEC2上にあり、クライアントのリクエストに応じてnginxがレスポンスを返すカスタムオリジン構成です。

今回は、この図の「CloudFront」と「ブラウザ」のキャッシュについて書きます。nginxについては書きません。

CloudFront

キャッシュの有効期限の管理 から概要だけ列挙しました。

コンテンツがキャッシュヒットするかの判断

  • 以下が完全に同じ場合に同一リクエストと判断し、キャッシュを返す
    • URLそのもの
    • HTTP Methods (GET, HEAD, OPTIONSのどれか)
    • 特定の HTTP Header (含めない設定にすることも可能)
    • Cookie (含めない設定にすることも可能)
    • クエリストリング (含めない設定にすることも可能)
  • 当然、同一とみなす条件を緩くすればキャッシュヒット率は上がる

どういった場合に同じコンテンツを返したい(または返したくない)のか設計しておくと良さそうです。

コンテンツのキャッシュ期間

  • CloudFront自身のTTL設定とorigin(配信元)の設定によって決まる
    • 関係するTTL設定は Minimum TTL, Default TTL, Maximum TTL の3つ
    • 関係するorigin設定は Cache-Control, Expires ヘッダーの2つ
    • Cache-Controlと各TTLで細かい挙動を設定することが可能

キャッシュの更新タイミング、その方法を設計しておくと良さそうです。

その他リンク

キャッシュの最適化やoriginごとの動作などについては、以下に章立てて説明されています。

ブラウザ

Cache-Control レスポンスヘッダ

  • キャッシュの許可や有効期限、更新確認などについて指定できる
  • 複数指定できるので、組み合わせて使う
  • no-cacheとno-sotre、publicとprivateの意味について注意が必要
    • no-cacheは「キャッシュしない」という意味ではない
    • privateを指定しておかないとキャッシュしてしまうCDNやProxyが存在する

HTTP 条件付きリクエスト

  • 検証子(etag, last-modified)を使ったGETで、リソースの更新確認ができる
    • 更新がない場合は304レスポンスが返され、リソースの再ダウンロードをスキップできる
  • ETag
    • 特定のバージョンのリソースを一意に識別するための値
    • If-None-Match リクエストヘッダと組み合わせて使われる
  • Last-Modified
    • リソースが最後に変更された日時
    • If-Modified-Since リクエストヘッダと組み合わせて使われる
  • If-None-Match と If-Modified-Since を同時に使用した場合、 If-None-Match が優先される

まとめ

冒頭で「キャッシュの使用が普及しつつある」と書きましたが、SEOのことやモバイルのネットワーク環境などを考えると、実際は必須のレベルなのではないかとも思います。
とはいえ、間違って設定するとトラブルになったり、システムが複雑になったりで避けている人も多いのも現状として感じます。

導入に敷居がある場合、まずは変更の少ないファイル(faviconなど)から設定してみてはどうでしょうか。
各設定の詳細についてはCloudFrontならAWSの公式ドキュメントが、ブラウザ(クライアント)についてはMDNがわかりやすいのでお勧めします。