Dev Study
← Webを支えるソフトウェア
レッスン 9 / 13·約 9 分·第3期 Webを支えるソフトウェア

キャッシュはどこに効くのか — 鍵と鮮度

リクエストがアプリケーションに届くまで
  1. ブラウザURL入力
  2. DNS名前→IP
  3. ルータ経路選択
  4. ロードバランサ振り分け
  5. Nginx受け口今ここ
  6. アプリ処理
  7. DB保存

取り次ぐ側が「そもそも上流に聞かずに済ませる」ための仕組みを見ます。第7週のCPUキャッシュと同じ言葉で語られますが、中身は別物です。

まず結論

「速い層に置いて、古くなったら捨てる」——この素朴な一言には、実は**3つの別々の概念**が混ざっています。時間で古くなる**失効**、不安全なメソッドが引き金の**無効化**、容量で押し出される**追い出し**です。

RFC 9111 が規定しているのは「保存してよいか」(§3)と「再利用してよいか」(§4。無効化の §4.4 を含む)です。**容量でどれを捨てるかは規定していません。**

? 読む前に予測

`Cache-Control: no-cache` が付いたレスポンスを、キャッシュは保存してよいでしょうか。

当てることが目的ではありません。外した予測ほど記憶に残るので、直感で選んでください。

抽象原理

3つの言葉を分ける

キャッシュの説明はたいてい「速い層に置いて、古くなったら捨てる」と要約されます。ただしこの一文には、引き金も結果も違う3つの概念が押し込まれています。

RFC 9111 が扱う3つの概念表
引き金 RFCの扱い 結果
失効 時間 §4.2 で規定 stale化。検証で復活できる
無効化 不安全メソッドの成功 §4.4 で規定 削除、または「無効」の印
追い出し 容量 ほぼ規定なし 消える

いちばん重要なのは失効が削除ではないことです。§4.3.4 の節タイトルは "Freshening Stored Responses upon Validation" — stale とは「捨てられた」ではなく「そのままでは使えない」状態です。

そして追い出しはRFCの管轄外です。evict の語は全文で1回、§5.3 Expires の説明文に現れるだけ。RFC が縛るのは「保存してよいか(§3)」「再利用してよいか(§4。無効化の §4.4 を含む)」で、どれを捨てるかは実装の自由です。

✓ ここまでの確認

「キャッシュキーはURIである」という説明の、最も正確な評価はどれですか。

具体実物

鮮度は引き算で決まる

鮮度の判定式は RFC 9111 §4.2 にそのまま書かれています。

RFC 9111 §4.2 の判定式コマンド出力
response_is_fresh = (freshness_lifetime > current_age)

左辺の freshness_lifetime は §4.2.1 の規則を上から評価し、最初に一致したものを使います。共有キャッシュなら s-maxage、次に max-age、次に Expires - Date。優先順位は s-maxage > max-age > Expires です。

右辺の current_age の基準は「保存してからの時間」ではなく、オリジンが生成した、または検証に成功した時点からの経過時間です。だから max-age=60 は「60秒間保存される」ではなく「age が60秒を超えたら stale とみなす」という意味になります。

ここで Expires に目を留めてください。絶対時刻なのに、寿命の計算では引き算に変換されます。

✓ ここまでの確認

`Expires` ヘッダは絶対時刻なのに、鮮度の計算では `Expires - Date` という引き算に変換されます。なぜでしょうか。

⇄ 2つを見比べる
具体例 A

HTTPの共有キャッシュ(RFC 9111)

上流に聞かずに答えるため、「いつまで正しいと見なせるか」を時間で持ちます。期限が切れても中身は残り、検証に成功すれば鮮度を取り戻します。容量が尽きたとき何を捨てるかはRFCが決めていません。

HTTPキャッシュが持つ判断表
保存してよいか §3 が規定
再利用してよいか §4 が規定(時間で判定)
古くなったらどうなる stale。検証で復活できる
容量が尽きたら 規定なし(実装しだい)
具体例 B

CPUのL1キャッシュ(第7週)

第7週では容量と速度の交換関係までを見ました。何を押し出すかは扱っていませんが、比較のために足します。メモリとは常につながっているので「何秒経ったら怪しい」という推定が要りません。あるのは容量の制約だけです。

L1キャッシュが持つ判断表
保存してよいか 常に置ける
再利用してよいか そこに在れば使える
古くなったらどうなる 時間で古くなる概念が無い
容量が尽きたら 押し出す(消える)

どちらも「速い層に置いて再利用する」仕組みです。ではなぜ、一方には「時間で古くなる」という概念があり、もう一方には無いのでしょうか。

それぞれのキャッシュが、正しさの判断を仰ぐ相手と、どういう関係でつながっているかを比べてください。

この章のまとめ

  • 「古くなったら捨てる」には3つの別概念が混ざっている。失効(時間・§4.2)、無効化(不安全メソッドの成功・§4.4)、追い出し(容量・ほぼ規定なし)。
  • 失効は削除ではない。 stale は「そのままでは使えない」状態で、検証に成功すれば復活する(§4.3.4)。
  • RFC 9111 が規定するのは「保存してよいか」(§3)と「再利用してよいか」(§4。無効化の §4.4 を含む)。置換アルゴリズムの規定は一切ない。
  • キャッシュキーは最低限メソッド+ターゲットURI(§2)。「URIだけ」は広く使われる実装上の簡略化。
  • 鮮度は freshness_lifetime > current_age。優先順位は s-maxage > max-age > Expires。Expires が引き算に変換されるのは時計のずれを減らすため(§4.2.1)。
  • no-cache は保存を禁じない。禁じるのは no-store。stale-while-revalidate は RFC 9111 ではなく RFC 5861 §3(Informational)。

自分の現場で確かめる

読んだだけでは身につきません。手元の環境で実際に見てみてください。

環境:

理解度チェック

読んだ直後は「分かった」と感じやすいものです。実際に解いて確かめてください。

問題 1 / 4正解: 0

`stale-while-revalidate` はどの文書が定義していますか。またその文書の位置づけは。

用語集(7語)
キャッシュキー (cache key)
保存したレスポンスの中からどれを使うかを選ぶための情報。RFC 9111 §2 は「最低限、リクエストメソッドとターゲットURI」から構成されると規定する。URIのみを使うのは広く見られる実装上の簡略化であって、規定ではない。Vary 対象のヘッダが加わることもある。
Vary
キャッシュキーの計算に効くヘッダ(§4.1 の節タイトルは "Calculating Cache Keys with the Vary Header Field")。Vary が挙げた全ヘッダが元のリクエストと一致しなければ、再検証なしにその保存済みレスポンスを使ってはならない。3点に注意: `Vary: *` は "always fails to match"(常に不一致)、ヘッダが**両方とも不在なら一致**、一致判定は空白の増減や行の結合を許した**正規化込み**でありバイト完全一致ではない。
失効 (expiration)
時間によって鮮度を失うこと。引き金は時間で、`freshness_lifetime > current_age` が成り立たなくなった状態を stale と呼ぶ(RFC 9111 §4.2)。stale は削除ではなく「そのままでは使えない」状態で、検証に成功すれば復活できる。
無効化 (invalidation)
安全でないメソッド(PUT/POST/DELETE 等)への非エラー応答が引き金となって、保存済みレスポンスを削除するか「無効」と印を付けること(RFC 9111 §4.4)。時間でも容量でもない第3の引き金。ただし無効化されるのは、そのリクエストが通った経路上のキャッシュだけ。
追い出し (eviction)
容量が足りなくなって保存済みのものを押し出すこと。RFC 9111 に置換アルゴリズムの規定は一切なく、`evict` の語は全文で1回、§5.3 Expires の説明文に現れるのみ。どれを捨てるかは実装の自由。
age
オリジンサーバが生成した、または検証に成功した時点からの経過時間(RFC 9111 §4.2)。「保存してからの時間」ではない。§4.2.3 によれば、経路上の各キャッシュでの滞在時間の合計に転送時間を足したものが `Age` として伝わり、受け取ったキャッシュは自分の滞在時間を足して current_age とする。
no-cache / no-store
`no-cache` は検証なしの再利用を禁じる指令で、保存は許される(§5.2.2.4)。`no-store` は保存そのものを禁じ、私的キャッシュと共有キャッシュの両方に適用される(§5.2.2.5)。ただし §5.2.2.5 自身が「プライバシを保証する信頼できる、あるいは十分な仕組みではない」と断っている。