Worker の前にキャッシュを置けるように!ヒットすれば CPU 課金はゼロだよ!
おつかれさま、しぃちゃんだよ!今日は Cloudflare のブログで見つけたニュースを紹介するね。「Worker が自分専用のキャッシュを前に持てるようになった」っていう発表なんだけど、地味そうに見えて実はコストにもパフォーマンスにも直結するすごい話なの。さっそく見ていこう!
Cloudflare Blog
なにが発表されたの?
発表されたのは「Workers Cache」っていう新機能。Worker のエントリーポイントのすぐ手前に、地域ごとに階層化されたキャッシュを差し込めるようになったんだって。設定は Wrangler の設定ファイルにたった 1 行足すだけでよくて、あとは組み合わせ自由(コンポーザブル)に使えるのが特徴なの。
しかも設定方法が親しみやすくて、Cloudflare が今まで使ってきた Cache-Control みたいな標準の HTTP ヘッダーをそのまま活用する形になっているんだ。専用のダッシュボード設定とかを新しく覚える必要がないの、これは嬉しいポイントだよね。
そして一番のハイライトはここ。キャッシュがヒットしたときは Worker のコード自体が実行されないから、CPU 時間の課金が発生しないんだって。もちろんリクエストとしてはカウントされるけど、レンダリングのための計算コストはゼロになるの。
今までどうだったの?
Workers が 2017 年に登場したときは、「キャッシュとオリジンの手前に Worker が立つ」っていう構成が基本だったの。つまりリクエストはまず Worker に届いて、そこからキャッシュやオリジンに問い合わせる、っていう役割分担だったんだ。
でも最近は Astro や Next.js、Remix みたいなフレームワークがこぞって Cloudflare 向けのアダプターを用意するようになって、Worker 自体がコンテンツを生成する「オリジン」になるケースがどんどん増えてきたの。
そうすると、本当はキャッシュしても問題ないはずのリクエストでも、キャッシュの仕組みが Worker より手前になかったせいで、毎回律儀に Worker のコードが動いてレンダリングし直しちゃう、っていうもったいない状態になっていたんだって。せっかく同じ答えになるとわかっているのに、そのたびに計算コストを払っていたイメージだね。
これからどうなるの?
Workers Cache が入ると、この順番が「キャッシュ → Worker → オリジン」にひっくり返るの。ゾーン単位の設定を別途管理する必要はなくて、Worker 自身が返す Cache-Control ヘッダーがそのまま設定になる、っていうシンプルな考え方なんだって。
これで、サーバーサイドレンダリングなアプリを動かしている開発者さんは、同じ結果を返せるリクエストについてはキャッシュヒットのたびにコストゼロで応答できるようになるの。パフォーマンスも上がるし、お財布にも優しくなる、まさに一石二鳥な仕組みだね。
深く潜ってみよう
ここからはしっかり技術的な中身を見ていくよ、しぃちゃん気合入れちゃう!
2 階層構造のキャッシュ: Workers Cache は「地域階層型(regionally tiered)」のキャッシュで、下層と上層の 2 段構えになっているの。下層はユーザーに一番近い Cloudflare のデータセンター内のキャッシュ、上層はネットワーク全体のフィル(埋め込み)を集約する層なんだって。リクエストはまず下層をチェックして、ミスしたら上層、そこでもミスして初めて Worker が実行される流れ。世界のどこかで最初の 1 回リクエストが上層を埋めると、それ以降は世界中どこからのリクエストでも上層からサーブできるようになるから、単純な 1 層構成のキャッシュよりずっと高いヒット率を狙える設計なんだ。
設定はほぼこれだけ:
{
"name": "my-worker",
"cache": { "enabled": true }
}
これを Wrangler の設定に足すだけでキャッシュが有効になるの。
レスポンス側のヘッダー例:
return new Response(body, {
headers: {
"Cache-Control": "public, max-age=300, stale-while-revalidate=3600",
"Cache-Tag": "products,product:123"
}
});
max-age はキャッシュが新鮮とみなされる秒数、stale-while-revalidate は期限切れ後も一旦古いコピーを返しながら裏側でこっそり更新する仕組み、Cache-Tag はあとでまとめてパージするための識別子として使うんだって。同じ URL でも複数のバリエーション(WebP 版と JPEG 版とか)を出し分けたいときは Vary ヘッダーで対応できるみたい。
パージもコードから呼べる:
await ctx.cache.purge({ tags: ["product:123"] });
特定のタグに紐づくキャッシュだけをまとめて消せるの。
マルチテナント対応: サービスバインディング経由で Worker を呼ぶとき、ctx.props にユーザー ID などを載せておくと、それがキャッシュキーの一部として組み込まれて、ユーザーごとに別々のキャッシュエントリが保証されるんだって。認証が絡む API でも安全にキャッシュできる作りになっているの。
entrypoint ごとに有効・無効を切り替え: 1 つの Worker が複数の named entrypoint を持っている場合、exports のマップで個別にキャッシュのオン・オフを設定できるんだって。たとえば認証を担当する entrypoint はキャッシュ無効のままにして、計算コストの高いバックエンド処理を行う entrypoint だけキャッシュを有効にする、みたいな使い分けができるの。
zone じゃなくて Worker 単位: 従来の Cache Rules や Page Rules はゾーン(hostname)単位の設定だったけど、Workers Cache は文字通り Worker に紐づく設定。管理すべきゾーン設定がそもそも存在しなくて、Worker が返すヘッダーがそのまま設定になるの。だから workers.dev 上でも使えるし、Workers for Platforms でテナントごとに分かれている場合もきちんと隔離される仕組みになっているみたい。
現時点の制限: ローンチ時点では、全プラン共通で Free プラン相当のキャッシュ可能サイズ上限(512 MB)が適用されるんだって。これは今後、段階的な展開の中でプラン別の上限に変わっていく予定とのこと。
料金の考え方: キャッシュヒット時はリクエスト課金だけで、CPU 時間の課金は発生しないの。ミスやバイパスの場合は通常通りリクエスト+CPU 時間が課金対象。キャッシュ機能そのものに追加の SKU はなくて、Tiered Cache やパージ、分析を使っても追加料金はかからないんだって。ただし静的アセットへのリクエストやサービスバインディング経由の Worker 間呼び出しは、それぞれ通常のリクエストレートで課金される点は覚えておきたいところ。
利用可能な範囲: Workers Cache は発表時点で、プランを問わずすべての Worker で使えるようになっているんだって。
これからの計画: Smart Placement との組み合わせ最適化、キャッシュ可能なレスポンスサイズ上限の拡大、Astro 以外(TanStack Start や Next.js など)のフレームワーク統合、そして完全削除ではなく「期限切れ」扱いにする ctx.cache.invalidate() の追加などが今後の予定として挙がっているよ。
まとめ
Worker の前に専用のキャッシュを配置できるようになったことで、キャッシュヒット時は Worker のコードが動かず CPU 課金もかからない、っていうのが今回の一番のポイントだったね。設定も Cache-Control ヘッダーとほんの数行の Wrangler 設定だけで済むから、フレームワーク経由で Worker がオリジン化している今のトレンドにすごくマッチしているなってしぃちゃんは思ったよ。パフォーマンスとコストの両方が改善するこの仕組み、今後の拡張も楽しみにしていようね!