logo hsb.horse
← ブログ一覧に戻る

ブログ

Cache-Control: max-age=3, must-revalidateを自分なりに整理する

マイクロキャッシングと呼ばれるCache-Control設定の挙動を整理。max-age=3とmust-revalidateの組み合わせがもたらす効果、時系列での動作フロー、具体的なユースケースをまとめる。

公開日:

Cache-Control: max-age=3, must-revalidate という設定について調べたので、忘れないうちに整理しておく。

この設定は「ごく短い間(3秒)だけキャッシュを利用し、期限切れ後は厳密にサーバーへ確認を行う」という挙動になる。一般的にマイクロキャッシングと呼ばれる手法で、リアルタイム性を維持しつつ、突発的なアクセス集中からサーバーを守るためによく使われるらしい。


各ディレクティブの意味

まず、それぞれのディレクティブが何を意味しているか確認しておく。

max-age=3

ブラウザやCDNなどのキャッシュサーバーに対し、**「このコンテンツは3秒間だけ新鮮である」**と伝える。この3秒間は、オリジンサーバーへのリクエストは発生せず、キャッシュから即座に返される。

must-revalidate

キャッシュの期限(3秒)が切れた後、**「オリジンサーバーへ確認(再検証)を行い、許可が出るまでは絶対に古いキャッシュを返してはいけない」**と強制する。

これがない場合、一部のキャッシュサーバーや設定によっては、オリジンサーバーがダウンしている時などに「とりあえず古いキャッシュを返す(stale content)」という挙動をとることがある。must-revalidateはそれを明確に禁止するためのものだ。


時系列での動作フロー

ユーザーがページにアクセスした時の動きをシミュレーションしてみる。頭の中で追いかけると理解しやすい。

タイミングユーザーの行動挙動ステータスコード
初回アクセスオリジンサーバーからデータを取得して表示200 OK
直後〜3秒以内再読み込み / 遷移オリジンサーバーへの通信は発生しない。ブラウザ(またはCDN)のキャッシュを表示200 (from cache)
3秒経過後再読み込み / 遷移キャッシュが「期限切れ」と判断される。ブラウザはオリジンサーバーへ条件付きリクエストを送る通信発生
→ 変更なしサーバーは「変更なし」と回答。古いキャッシュを再び3秒間有効化。コンテンツのダウンロードは発生しないため軽量304 Not Modified
→ 変更ありサーバーは新しいコンテンツを返す200 OK

ポイントは、3秒経過後に304 Not Modifiedが返るケースだ。コンテンツ本体のダウンロードが発生しないので、通信量もレイテンシも最小限で済む。ここが効いてくる。


この設定のメリット

主に**「リアルタイム性が重要だが、アクセス数が非常に多いサイト」**で絶大な効果を発揮する。覚えておきたい3点。

サーバー負荷の劇的な低減

例えば、秒間1,000リクエストが来るサイトの場合、max-age=3があれば、理論上オリジンサーバーへのリクエストは「3秒に1回」だけで済む。残りの2,999回はキャッシュで捌ける(CDN併用時)。

たった3秒のキャッシュでも、高トラフィック環境では圧倒的な差になる。

ほぼリアルタイムな更新

最長でも3秒待てば新しい情報が反映される。「完全なリアルタイム」ではないが、多くのユースケースで十分許容できる範囲だ。

古い情報の表示防止

must-revalidateにより、期限切れ後にサーバー確認なしで古い情報が表示されるリスクを排除できる。情報の正確性が重要な場面では必須の設定だ。


具体的なユースケース

「どんな場面で使えるか」を自分なりに考えてみた。

向いているケース

  • ニュースサイトのトップページ・一覧ページ: 新着記事が即座に反映される必要があるが、秒単位の遅延は許容できる。アクセスが集中しやすい面でもある
  • ECサイトの在庫状況表示: 「残りわずか」の表示が数秒遅れても致命的ではないが、売り切れた商品が購入可能に見えるのは困る。must-revalidateで古い在庫情報の表示を防げる
  • イベントやキャンペーンのLP: 公開直後にSNS等から大量のアクセスが来る。マイクロキャッシングで最初の波を凌ぎつつ、内容更新があればすぐ反映できる
  • ダッシュボードのサマリー表示: リアルタイムグラフほどの即時性は不要だが、最新のKPIを反映したい画面。ポーリング間隔が3秒以上ならこの設定と相性が良い
  • APIレスポンス(リスト系): 一覧取得APIのレスポンスにこのヘッダを付与することで、CDNレイヤーでキャッシュし、オリジンサーバーの負荷を軽減できる

向いていないケース

  • 静的アセット(CSS/JS/画像): 頻繁に変更されない。ファイルハッシュ付きの命名 + max-age=31536000,immutableのほうが適切
  • ブログの記事詳細ページ: 公開後に頻繁に更新されることは少ない。もっと長いmax-ageを設定して良い
  • リアルタイムチャットやWebSocket通信: そもそもHTTPキャッシュの対象外。3秒の遅延すら許容できない場面には不向き
  • ユーザー固有のコンテンツ: マイページなど、ユーザーごとに異なるレスポンスはCDNでの共有キャッシュに適さない。privateディレクティブとの組み合わせを検討すべき

注意点

忘れがちな落とし穴も書いておく。

3秒ごとの通信発生

3秒経過後は必ず条件付きリクエストが発生する。max-ageが長い設定と比べると、ネットワークレイテンシの影響を受けやすい。低帯域環境でのUXには注意が必要だ。

オフライン時の挙動

must-revalidateがあるため、ネットワークが切断されている場合やサーバーがダウンしている場合、キャッシュが残っていても表示されずエラーになる可能性が高い。「古いものを出すくらいならエラーにする」という挙動だ。

これを許容できない場合は、stale-while-revalidatestale-if-errorとの組み合わせを検討する。


まとめ

Cache-Control: max-age=3, must-revalidateは、**「鮮度は命だが、サーバーを落としたくない」**というバランスを攻めた設定だ。

マイクロキャッシングという名前はやや大げさに聞こえるが、やっていることはシンプルで「ほんの数秒だけキャッシュする」それだけだ。その数秒が高トラフィック環境では劇的な効果をもたらす。

設定する前に、自分のサービスが「向いているケース」に該当するか確認すること。静的アセットや更新頻度の低いページにまでこの設定を適用してしまうと、無駄な再検証リクエストが増えるだけなので注意。