0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

キャッシュの挙動がわからなさすぎてハマった件

Posted at

はじめに

皆さんはキャッシュを利用しているでしょうか?
キャッシュはコンテンツの取得を高速化するためによく使われますが、正しく理解して使わないと「なぜかコンテンツが更新されない!?」といった罠にハマることがあります。

今回は、特にCDNでのキャッシュ挙動に見事にハマってしまったので、自戒を込めて整理・勉強した内容を記事にまとめました。

キャッシュの設定について

キャッシュの挙動を理解するために、以下のような通信経路を考えます。

  1. ブラウザがコンテンツを要求する
  2. 通信がCDNを経由するが、CDNにキャッシュが存在しないためオリジンへ要求が送られる
  3. オリジンがCDN経由でブラウザにコンテンツを返却する。このとき、オリジンで設定された Cache-Control に従ってCDNにキャッシュが保存される
  4. ブラウザにコンテンツが表示され、同じくオリジンで設定された Cache-Control に従ってブラウザにもキャッシュが保存される
  5. 以降の通信では、ブラウザまたはCDNに保存されたキャッシュからコンテンツが返却される

image.png

キャッシュの挙動は、オリジンからのレスポンスヘッダ Cache-Control で制御できます。代表的なディレクティブを以下にまとめます。

  • max-age
    ブラウザ側でのキャッシュ保持期間を設定します。マネージドなサービスだと ブラウザではなくCDNも設定できることがあります。
  • s-maxage
    max-age の CDN 版です。CDN 側でのキャッシュ保持期間を設定します。
  • no-cache
    キャッシュを使用する前にオリジンへアクセスし、コンテンツが更新されていないか確認します。更新されていた場合はキャッシュを更新します。
  • must-revalidate
    キャッシュの有効期限が切れた際に、必ずオリジンへアクセスして更新を確認します。
  • proxy-revalidate
    must-revalidate の CDN 版です。
  • no-store
    キャッシュを一切保存しない設定です。
  • stale-while-revalidate
    キャッシュを再検証している間、古いキャッシュを再利用できる期間を設定します。
  • stale-if-error
    オリジンがエラーを返した場合に、古いキャッシュを利用できる期間を設定します。

似ている設定の差分

no-store vs no-cache

  • no-store はキャッシュを一切保存しません。
  • no-cache はキャッシュを保存しますが、使用する際に必ずオリジンへ確認(検証)を行います。

そのため通信経路上の動作には大きな違いはなく、「キャッシュをストレージに残すかどうか」が主な差分になります。

max-age=0 vs no-cache

  • max-age=0 は「キャッシュの有効期限が切れている状態」を意味します。この場合、must-revalidatestale-while-revalidate などの再検証関連ディレクティブが動作します。※仕様上は、そのように区別できますが実際は、no-storeと同様に動く場合もあります。
  • no-cache は常にオリジンへの検証が発生します。

no-cache vs must-revalidate

  • no-cache は常にキャッシュ使用前に検証を行います。
  • must-revalidate はキャッシュの有効期限が切れた後にのみ検証を行います。

したがって、
no-cache = max-age=0, must-revalidate
と考えることができます。

max-age=600 vs max-age=600, must-revalidate

どちらも有効期限(600秒)を過ぎると最新のコンテンツを取得しに行きます。
ただし挙動に以下の違いがあります。

  • max-age=600 の場合、オリジンでの検証が失敗すると古いキャッシュを返す可能性があります。
  • max-age=600, must-revalidate の場合、オリジンでの検証が失敗すると 504 Gateway Timeout を返します。

今回のハマった件

キャッシュ設定を変更した際に、想定外の挙動が発生したため、その検証を行いました。

前提

あるコンテンツ管理システム(CMS)において、「CDNのキャッシュを無効化する」設定を行いました。
ただし、このシステムでは Web 管理画面からしかキャッシュ設定を変更できず、変更可能なディレクティブは以下の4つのみでした。

  • max-age
  • s-maxage
  • stale-while-revalidate
  • stale-if-error

設定変更内容は以下の通りです。

ヘッダー 変更前 変更後
max-age 3600 0
s-maxage 3600 0
stale-while-revalidate 86400 86400
stale-if-error 86400 86400

なお、Web管理画面上では stale-while-revalidatestale-if-error を設定していませんでした。
しかし、実際にはシステム側でデフォルト値(一日)が自動的に設定されており、この仕様に気づかずハマってしまいました。

起きた事象

結論から言うと、後述する AWS CloudFront のキャッシュポリシーをいろいろ変更しても、同じ現象を再現することはできませんでした。(この事象が起きたのはCloudfrontではないCDNです。)
そのため、ここでは実際に発生した事象のみを記録します。

変更手順は以下の通りです。

  1. CMS 上でキャッシュ設定を無効化する
  2. コンテンツを更新する
  3. コンテンツにアクセスする
    → キャッシュ変更前に設定されていた stale-while-revalidate の影響で、更新前のコンテンツが返却される
  4. もう一度コンテンツにアクセスする
    → 更新後のコンテンツが返却される
  5. しばらく時間を置いて再度アクセスする
    → なぜか更新前のコンテンツが返却される(⁉⁉)

原因考察

おそらく、CDN ごとに s-maxage=0 を指定した際の「古いキャッシュの扱い方」に差があるのだと思われます。

  • s-maxage=0 を指定した時点で、常に古いキャッシュを削除する実装
  • 古いキャッシュを削除せず、ただし s-maxage=0 のため新しいキャッシュを保持しない実装

このように CDN の実装差によって挙動が異なり、その結果として今回の事象が発生したのではないかと考えています。今回発生した事象は後者のような動きをしているのだと思っています。

検証環境

上記の減少の再現を目指して。AWSのCloudfrontとLambda関数を用いて試みました。

検証環境は以下の記事と同様のものを作成しました。またCloudfrontではキャッシュポリシーを無効化し、「Use legacy cache settings」を有効化しています。
https://zenn.dev/devcamp/articles/e9877f79230ef2 

変更手順

今回はCloudfrontでの挙動を見たいので、max-age=60 の値を変更していきます。max-ageだけを指定するとCloudfrontのキャッシュの時間になります。

手順

  1. Lambda関数で "max-age=60, stale-while-revalidate=3600, stale-if-error=3600"にする
  2. cloudfrontにアクセスして、キャッシュを保存させる
  3. max-age=0にする
  4. キャッシュ保存期間終了後に、何度かcloudfrontにアクセスして、コンテンツを確認する

以下が結果になります。
image.png

仕様上だと、stale-while-revalidateが動作してもおかしくないのですが、max-age=0にした後はAgeがなくキャッシュが働いていないのがわかります。

結論:s-maxage=0には注意

基本的に、普段使っている分には何も問題ないと思いますが、CDNによって挙動が違うことを実感しました。
s-maxage=0だと、CDNによって処理が違うように感じたので、個人的にはリアルタイム性を追求しないのであればs-maxage=1を設定しておくと、問題ないのかなと思いました。実際、s-maxage=1だとCloudfrontでもstale-while-revalidateが動作してくれます。
またマネージドなCDNを使う場合でも、いつでもキャッシュクリアできる方法を準備しておくのも重要です。何かあった場合にとりあえずキャッシュクリアすれば最新版を取得できれば心配を軽減できます。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?