要約

  • Cache-Status は、各キャッシュのローカルヒット、転送理由、次ホップの状態、残り鮮度、保存、要求集約を、オリジン側から利用者側へ並ぶリストとして表現する。
  • 記載の有無と多くのパラメーターは各キャッシュが選ぶ。hit は古い応答でも成立し、TTL はローカル計算であり、正しい構文や順序は送信者の認証や経路の完全性を保証しない。
  • 運用では生のリストを保存し、Cache-Control、Age、Via、トレース、内部イベント、利用者確認と突き合わせ、応答を届ける権限と、その結果を説明・判定する権限を分ける必要がある。

「HIT」の一語が強すぎる現場

ニュースサイトが訂正を公開した。オリジンでは新しい本文が返る。それでも一部読者には旧稿が見える。エッジで取得した応答には次の行があった。

Cache-Status: Edge; hit; ttl=120

障害室では、キャッシュが古い記事を持ち続けた、あと二分で自然に直る、という説明が即座に共有される。しかし、この行が直接述べるのはもっと狭い。

RFC 9211hit は、このキャッシュが今回の要求を転送せず、キャッシュから応答を得たことを示す。新鮮だったとは限らない。条件により古い応答を転送せず使った場合もヒットになり得る。ttl=120 は、このキャッシュが応答ヘッダー送信時付近で計算した残り鮮度であり、ヒューリスティックやローカル設定を含む場合がある。

この一行だけでは、訂正の invalidation がどの層に届いたか、要求に適した言語・利用者・版をキーが分離したか、記事が真正か、二分後に読者が新稿を見るかは分からない。

短い証言を広い判決へ膨らませないことが、Cache-Status を有効に使う第一条件である。

私有の暗号表を共通語へ変えた

キャッシュは以前から独自の診断ヘッダーを付けていた。HIT と MISS だけの製品もあれば、メモリー、ディスク、ノード、再検証を独自コードで示す製品もあった。収集はできても、意味の解読はベンダーに依存した。

Cache-Status は HTTP Structured Fields の List として、各キャッシュの記述を共通構造に置く。最初のメンバーはオリジンに最も近く、最後は利用者に最も近い。リバースプロキシ、shield、edge が既存値を保ったまま順に追加すれば、一つの応答に多層の処理履歴が現れる。ユーザーエージェント自身が追加する場合は末尾に来る。

共通化の利点は HIT/MISS の表記統一だけではない。URI がなかったのか、Vary による選択が失敗したのか、要求側の指示で使えなかったのかを区別できる。次ホップの 304、保存、要求集約も機械的に扱える。

ただし、履歴は参加者の協調で成立する。キャッシュは常時、設定時、デバッグ要求時など、いつフィールドを出すか自ら決める。追加時には既存値を保持すべきだが、その保持に耐改ざん性はない。記載しないキャッシュ、情報を削るゲートウェイ、識別子を抽象化する運用もあり得る。共通語は真実を強制せず、真実について互換的に語る器を提供する。

名前は名乗りであって資格証明ではない

各メンバーは String または Token の識別子を持つ。製品名、サービス名、ホスト名、IP アドレス、生成文字列のいずれでもよい。柔軟である一方、その文字列を特定会社や実インスタンスへ暗号学的に結び付ける規則は RFC 9211 にない。

観測点で保存した生の応答は、「そのメッセージにその名乗りが含まれた」という直接証拠になる。名乗りを資産やキャッシュ層に結び付けるには、経路設計、設定版、アクセス制御された収集などが必要だ。内部状態まで確認するには、別のテレメトリーが要る。

CDN がコンテンツを配り、同時に配り方の説明も書くこと自体は合理的である。問題は、その説明だけが唯一の記録になることだ。重大障害、侵害、契約上の争いでは、オリジンログ、利用者側観測、独立保持されたトレースが反証可能性を支える。

ヒットは正解印ではない

hit が true なら、今回の要求はこのキャッシュ内で満たされ、上流へ送られなかった。保存応答を基に 304 や 206 を構成しても、今回の処理が上流へ進まなければヒットになり得る。逆に、対象が保存されていても古さや範囲不足のため転送したならヒットではない。

保存、選択、再利用、再検証、古い応答の利用を許すのは RFC 9111、Cache-Control、Expires、validator、Vary、要求ディレクティブ、stale-if-error などである。Cache-Status は決定後の報告であり、禁止された再利用を許可する制御面ではない。

したがって、規範上の許可、実設定、実行結果の報告、アプリケーション上の正しさを分けなければならない。設定が利用者境界をキーに含め忘れた場合、キャッシュは設定どおり正確にヒットし、フィールドも正直でありながら、サービス全体として重大な誤配信を起こせる。

転送理由は原因候補を分ける

fwd は要求がオリジン方向へ進んだ理由を Token で示す。

uri-miss は URI に合う応答がない。vary-miss は URI が合っても保存済み Vary と要求ヘッダーから適切な表現を選べない。request は新鮮な候補があるが要求の意味が利用を許さない。stale は候補が古い。partial は範囲が不足する。method はメソッド意味論、bypass は設定による非処理を示す。実装が URI と Vary を区別できない場合には一般的な miss を使える。

各値の対処は違う。uri-miss 増加は URL 変更、vary-miss は言語や圧縮の新次元、request はクライアントの再検証指示、bypass は意図した除外を示すかもしれない。詳細を再び MISS 一つに集約すれば、標準化で得た観測能力をダッシュボードで捨てることになる。

TTL、保存、集約、キーは別の証言である

fwd-status は次ホップが転送要求に返した状態コードを示す。古いオブジェクトを再検証して上流が 304 を返し、利用者には 200 を返す場合、その差を記録できる。ただし validator が正しい業務データに対応したかまでは証明しない。

ttl は当該キャッシュによる残り鮮度の秒数で、負にもなり得る。Age はオリジンが生成または検証してからの経過を、キャッシュ滞在と伝送を含め推定する。両者は関係するが同じではない。Date、指示、validator と合わせて読む必要がある。

stored は転送応答を保存したという主張であり、将来も残る保証ではない。collapsed は複数の上流要求をまとめたかを示す。集約はオリジン負荷を抑える反面、一つの上流結果を多くの待機要求へ配るため、誤りの影響も集中する。

key は使用したキャッシュキーの表現で、実装固有でもよい。クエリー正規化、Vary、言語、テナント境界の調査に強いが、キー変換を外部へ教え、キャッシュポイズニングを助ける危険がある。detail は送信したキャッシュだけが意味を定める。同じ MEMORY でも製品間で同義とは限らない。

多くのパラメーターは任意である。欠落は false ではなく「このメッセージにはその主張がない」。未知を否定へ変える分析基盤は、キャッシュ以上に強い断言を勝手に作ってしまう。

見えるのは経路ではなく開示された経路

設計上はオリジンキャッシュ、shield、edge、企業プロキシ、ブラウザーが並んでいても、利用者が五つのメンバーを見るとは限らない。ブラウザーは追加しないかもしれない。edge は認証済みデバッグ時だけ出すかもしれない。セキュリティ装置は診断フィールドを落とすかもしれない。

観測されたリストは、観測点まで届いた自己申告の順序であり、キャッシュ発見プロトコルではない。Via は転送受信者とプロトコル情報を補い、Proxy-Status はより広いプロキシ処理やエラーを伝える。役割は異なり、一方が他方の完全性を保証しない。

実経路で試験する必要がある。各層を通る制御要求を送り、複数地点で捕捉し、順序、保持、識別子を確認する。ヒット、URI miss、Vary miss、再検証、許可された stale、bypass、集約をそれぞれ作る。中間装置や CDN 設定の変更後に再試験する。構成図は期待を示すだけで、実行を証明しない。

キャッシュキーの妥当性は別に残す

キャッシュキーには少なくともメソッドと対象 URI が入り、Vary が要求ヘッダーの次元を加える。No-Vary-Search のような仕組みは、クエリー要素の一部をキー比較から外せるという等価性を応答が宣言する。これは選択前の制御情報である。

Cache-Status は選択後に来る。hit は保存応答を選んだことを、key はキーの表現を示せる。しかし、その等価性がアプリケーションにとって安全だったか、実装が正しかったか、異なる利用者の要求が本当に交換可能だったかは証明しない。

キー規則、設定版、安全なキー指紋、言語・認証・テナント・個人化の境界試験を保持しなければならない。そうしなければ、Cache-Status は危険な決定が完全に実行されたことだけを精密に報告する。

認証するなら別の設計が要る

RFC 9211 はメンバーの署名や MAC を定義しない。裸のフィールドは耐改ざん証明ではない。HTTP Message Signatures は選択した HTTP コンポーネントを覆えるが、要求コンポーネント、鍵、アルゴリズム、署名者権限、時間、失敗処理をアプリケーションが規定する必要がある。

Cache-Status を保証したいなら、署名対象へ明示的に含めなければならない。さらに、多層経路のどこで署名したかを扱う必要がある。後段キャッシュは先の署名後にメンバーを追加できる。有効な署名は署名者と被覆コンポーネントの関係を証明するが、キャッシュ内部のヒット事実を直接測定しない。

通常のサービスでは、認証済みデバッグ、制御された捕捉、共通トレース ID、別基盤に保存した内部イベントで十分な場合も多い。重要なのは、保証の由来と限界を明文化することである。

開示は攻撃面にもなる

RFC 9211 は、攻撃者が Cache-Status からキャッシュや他コンポーネントの挙動を探り、共有利用者の活動を推測できると警告する。保存の有無は機密データへのタイミング攻撃を助け、キーは変換規則を明かしてポイズニングを助ける。単なる難読化では根本リスクを消せない。

対策は、フィールドを省略する、許可されたクライアントだけへ送る、機微パラメーターだけを制限する、の組合せになる。つまり開示はアクセス制御の対象である。

公開最小プロファイルは層を表す安定した仮名と主要結果だけにする。認証済みプロファイルは TTL、次ホップ状態、保存、集約、安全なキー表現を追加する。高機密系は外部に出さず、独立した内部観測面へ豊富なイベントを送る方法もある。

最大開示と完全沈黙の中間に、必要な相手へ必要な証拠を渡し、同時に供給者以外も記録を持つ設計がある。

調査は複数の証人を集める

生の応答を保存する。観測点、時刻、メソッド、URI、選択に関係する要求フィールド、状態、Date、Age、Cache-Control、Expires、ETag、Last-Modified、Vary、Via、Proxy-Status と Cache-Status の全順序を一緒に残す。

各メンバーを期待する層、ソフトウェア版、設定世代へ結ぶ。キーが必要なら、広いチケットへ生値を貼らず、鍵付きハッシュや許可済み表現を使う。

次に内部事象で裏を取る。ヒットなら検索イベントとオブジェクト、fwd=stale; fwd-status=304 なら条件要求、集約ならグループと待機数、保存なら保存イベントが必要だ。最後に、配られた表現をその利用者、言語、テナントのオリジン版と比較する。パージ後に MISS になっても、読者が正しい記事を見たとはまだ言えない。

標準を実行事実へ変える試験

既知のヒットを作り、上流要求がないことを確認する。URI と Vary の miss を分け、再検証で上流 304 と最終状態を区別する。許可された stale で負 TTL を確かめる。同時 miss を集約し、オリジン要求数と待機者数を照合する。

開示も試す。公開応答に機微な key と detail がないこと、認証済みデバッグで承認項目だけ増えること、edge・shield・ゲートウェイ更新後も順序と既存値が保たれること、未知拡張を勝手に解釈しないことを確認する。署名を使うなら対象変更で検証が失敗し、Cache-Status が被覆されることを証明する。

IANA Cache-Status レジストリ は共有パラメーター名と型を調整し、HTTP Field Name Registry は恒久的な List フィールドとして記録する。登録は語彙の事実であり、製品採用や個別応答の真実の証明ではない。

証拠記録