Claude が書いた記事
CDN の cache って結局なに見てるん? ── shield と cache key を解体する
Cloudflare をモデルに CDN の内部を解剖した学習ログ。shield / PoP の規模 / cache key / KV の関係を、図 3 枚で 30 秒で復元できるよう整理。
俺の最初の疑問
ニュースで Cloudflare の障害だの「大規模 DDoS を耐えた」だの、よく目にする。 ただ CDN って結局、内部で何をしているのかずっと曖昧やった。
CDN の中で何が起きてんねん? shield と cache って、何を見て何を判断しとるん?
公開情報の厚さで Cloudflare をモデルに、ここを解体する。
まず一言でいうと
CDN は 「世界中の PoP に置いた『でかい KV ストア (cache)』を、shield 役の中間層を挟んで漏斗状に重ねたもの」。
入ってきたリクエストから cache key を計算して、その key で KV を引く。 HIT したらキャッシュを返す。MISS したら shield (上位層) に渡す。さらに MISS したら origin に取りに行く。 これだけ。
派手な印象に反して、中身は dict と漏斗 の合わせ技。
何と比べるとわかるか
| 普通の Web サーバー | CDN | |
|---|---|---|
| 受け持つ場所 | 1 拠点 | 世界中の PoP (Cloudflare で約 330 ヶ所) |
| キャッシュ | 単一 (なくてもいい) | 多段 (Edge → Upper-tier → Cache Reserve → Origin) |
| 経路選択 | クライアントが直接来る | Anycast / DNS で最寄り PoP に振り分け |
| origin 保護 | 自分で TCP 守る | upper-tier (shield) が前段で吸収 |
| 識別の単位 | URL でファイルを探す | cache key (URL + α) で KV を引く |
要するに CDN = 多段キャッシュ + 動的ルーティング。Web サーバーを「重ね合わせて、間を漏斗で繋いだ」構造に近い。
何が問題なのか
CDN を生んだ動機は 2 つだけ。
1. 物理距離
光速の限界で、地球の裏側を往復すると 最低でも 150ms 級 のレイテンシが出る。 ユーザー近くの PoP に持ってこないと Web は遅すぎる。だから「世界中に PoP を置く」。
2. origin への殺到
Edge を世界中に置くと、新着コンテンツの初回アクセスで 数百ヶ所の Edge が同時に origin に殺到する (thundering herd)。 これを防ぐために、上位層 (shield / mid-tier) を間に挟んで漏斗状にする。 origin から見える「リクエスト元の数」が N から 1 まで絞られる ── これが「盾」の効果。
図で見る
Client から Origin までの経路と、shield (= upper-tier) がどこにいるか:
PoP の中身の規模感。Edge と Upper-tier の違いは「役割」ではなく「規模と立地」:
1 リクエストの内部フロー。cache key を「作る」ところ、それを使って cache を「使う / 作る」分岐:
混乱しやすいポイント
ここからが認知のズレを直すパート。順に潰す。
shield は固定の 1 ヶ所ではない
Fastly や AWS CloudFront は顧客が Origin Shield を 1 つ指定する固定運用。
一方 Cloudflare は Origin Shield という独立機能を持たない。代わりに Tiered Cache の upper-tier がその役を兼ねていて、しかも cache key ごとに upper-tier が動的に選ばれる (Smart Tiered Cache)。
つまり Cloudflare では「shield = 1 ヶ所の関所」ではなく、cache key 単位で別の関所が立つ。
PoP に「専用キャッシュサーバー」は存在しない
Cloudflare の設計哲学は “every server runs every service”。 1 つの PoP の中の全サーバーが同じスタック (cache / DNS / WAF / Workers / TLS 終端) を動かしていて、L4 LB (Unimog) で到着パケットを均等分散する。
cache key の hash で責任サーバーが決まる (PoP 内 sharding) ので、ある URL のキャッシュは PoP 内の 1〜数台にだけ存在する。PoP 内にも小さな漏斗構造がある、と思っておくと正確。
cache key の主語を整理
ここが一番ハマる。
| 主語 | 役割 |
|---|---|
| クライアント | URI を送るだけ。cache key の存在も知らない |
| CDN edge software | cache key を計算する。KV lookup にも使う。作るのも使うのも edge software |
| サイト運営者 | cache key の 計算ルール (Cache Rules / Custom Cache Key) を設定する。計算自体には関与しない |
cache key は CDN の内部概念。クライアントには見えない。
URI と cache key は別物
cache key は URI を素材にして作るが、URI そのものではない。
- 同じ URI でも Cookie やヘッダを cache key に含める設定 をすれば別キャッシュ (ユーザーごとに別)
- 違う URI でも
utm_sourceのような query を計算から除外する設定 をすれば同じキャッシュ
「URI ⊆ cache key の入力」。デフォルトでは URI ≒ cache key だが、設定でズレる。
cache key は文字列だが、内部は固定長 hash
論理表現: "https://example.com/article/123?ref=twitter"
物理表現: 0xa3f1e8b7... (例えば 32 byte の hash)
固定長 hash にする理由は 3 つ:
- 比較が一瞬で終わる (1〜2 命令で済む、可変長文字列だとループ)
- PoP 内 sharding が均等になる (hash は統計的に均等分布)
- メモリ・ディスク効率が良い (200 byte の URL → 32 byte の hash)
cache 本体は KV ストアそのもの
CDN の cache は概念的に でかい dict。
cache = {
"0xa3f1e8b7...": {
"response": <HTTP response body + headers>,
"metadata": {
"stored_at": "2026-05-26T12:34:56Z",
"ttl_seconds": 3600,
"etag": "W/\"abc123\"",
}
},
...
}
実装上は LRU 退避 / TTL 切れ / SSD spillover / サーバー間分散があるが、抽象としては dict。 ちなみに Cloudflare の “Workers KV” は別物の顧客向け製品。文脈で判別する必要がある。
TTL は cache key には入っていない
TTL を key に混ぜると、時刻で key が変わって永遠に MISS。 TTL は value 側のメタ情報 として格納される。
lookup は 2 段階:
- ステップ A: cache key で「どのエントリを引くか」を決定
- ステップ B: 引いたエントリの TTL を見て「新鮮か」を判定
そして「そもそもキャッシュ対象か」は ステップ A 以前 で Cache-Control や Cache Rules によって判定される。3 層に分離している。
cf-cache-status で各層が透ける
| 値 | 意味 |
|---|---|
MISS | ステップ A で key が無かった |
HIT | ステップ A で key あり、ステップ B でも新鮮 |
EXPIRED | A で key あり、B で TTL 切れ。origin に取り直した |
REVALIDATED | EXPIRED 後、origin が 304 Not Modified を返したので value を再利用 |
BYPASS | A 以前で「そもそもキャッシュしない」判定 |
cf-cache-status を読めば、どの層で何が起きたかが見える。デバッグはまずこのヘッダから。
たとえ話
- shield = 城門。城の周りには無数の道があるが、外からの来訪者 (リクエスト) は 1 つの門 (upper-tier) を通ってしか城内 (origin) に届かない。
- cache key = 倉庫の棚の住所。同じ住所の箱は同じ棚。同じ住所の箱が一個も無ければ外に取りに行って、その住所に置く。
- cache = でかい dict。Python の dict にサイズ制限と TTL と分散を足したもの。だいたいそれ。
- PoP = 同じ機械を大量に並べたデータセンター。Edge も Upper も「特別な装置」ではなく、ハードの数違い。
ニュースを読むための変換表
| ニュースの言葉 | つまり何の話? |
|---|---|
| Cloudflare の障害 | edge software のバグ・設定ミス・ネットワーク経路問題が世界規模で同時発火する CDN 構造の代償 |
| 大規模 DDoS を耐えた | edge で攻撃を吸収して origin に届かせなかった話。盾の効果が見えた瞬間 |
| Cache hit rate | origin に届かず edge で返せた割合。CDN の費用対効果の主指標 |
| Tiered Cache | shield 役の upper-tier を入れる Cloudflare の機能名 |
| Cache Reserve | LRU で消えない永続キャッシュ層 (R2 ベース)。長尾コンテンツ用 |
| Argo Smart Routing | origin への経路を Cloudflare の網内で最適化する有料機能 |
| Workers | edge で動くカスタムコード。cache lookup の前後に割り込める |
| Anycast | 「同じ IP を世界中に配って、BGP で最寄りに届ける」ネット技術。CDN の入り口の仕組み |
| Quicksilver | Cloudflare 内製の KV 配布システム。purge を世界に数秒で伝播する裏方 |
shield と cache key の中身は割れた。次は現場の俺として「で、どう設計を選ぶんや?」。
- 配信を設計するとき、shield (upper-tier) を効かせるか、ヒット率を捨てて origin に近づけるか。 判断軸は「origin の処理能力 × ヒット率 × cache key の切り方」。cache key に Cookie を含めた瞬間ヒット率が落ちる、まで込みで選べるか。
- 責任境界:どこまでが CDN (edge) の責任で、どこからが origin の責任か。 障害が出たとき
cf-cache-statusのどの値なら CDN 側、どこから origin 側か、切り分けられるか。
これに答えられると強い。「CDN の中身を語れる」の一歩先 ── ヒット率と origin 保護を天秤にかけて配信を設計できる側に立てる。普段触る Front Door でも迫られる同じ判断や。
この記事の続きとして、未来の自分が次に掘るといいトピック。
- Quicksilver (設定の世界配信) ── purge やルールを数秒で全 PoP に配る KV 配布システム。CDN の”制御面”がなぜ速いかの核。
- Pingora (Cloudflare の Rust 製 proxy) ── NGINX を置き換えた自社プロキシ。なぜ書き直したかを追うと CDN のボトルネックが見える。
- PoP 内 sharding の hash (consistent hash / rendezvous) ── 1 拠点の中でどのサーバーがどの URL を持つか。キャッシュ分散の基礎アルゴリズム。
- Workers (エッジで動くコード) ── cache lookup の前後どこに割り込むか。CDN が”実行環境”に化ける話。
- Akamai との設計比較 ── Tiered Distribution との思想の違い。CDN 各社の設計判断を相対化できる。