Cloudflare Workers KVのCold Start
公開日:2025-02-05
結論
- Cloudflare Workers KVは読み取り処理が多いアプリケーション向けに最適化されている
- Cloudflare Workers KVの初回読み取りはEdgeにキャッシュされておらずストレージへデータを取得するため、Cold Startが発生し低速となる。以降はEdgeにキャッシュされるため高速に読み取りが可能
- Edgeのキャッシュに対するデータスピンダウンはおそらく50秒と推測(次回アクセスまでに50秒以上放置するとEdgeのキャッシュがクリアされる)
- Cloudflare Workersの利点として挙げられている
High performance runtime with no cold starts
という記述は、Workers自体のCold Startを指しており、KVのCold Startとは異なるので注意
はじめに
RooCodeの練習として、お気に入りのお店を記録・管理できるWebアプリケーションを開発していた際に、Cloudflare Workers KVのCold Startに少し悩まされたので備忘録として残します。間違いや誤解があれば指摘いただけると幸いです。
Webアプリケーションの構成
-
開発構成は以下の通り。
Loaclのディレクトリで/front
と/back
で分けて開発。- editor:VSCode + RooCode
- フロントエンド:Next.js(Local)
- バックエンド:Cloudflare Workers + Hono(Local)
- データのやり取り:REST API
- データベース:Cloudflare D1(Local)
- 画像ストレージ:Cloudflare R2(Local)
- Cache:Cloudflare Workers KV(Local)
- 認証:Supabase
-
本番構成は以下の通り。
開発環境で作成したものをGitHub Actionsでデプロイする形です。- フロントエンド:Next.js(Vercel)
- バックエンド:Cloudflare Workers + Hono
- データのやり取り:REST API
- データベース:Cloudflare D1
- 画像ストレージ:Cloudflare R2
- Cache:Cloudflare Workers KV
- 認証:Supabase
- CICD:GitHub Actions
今回はRooCodeの練習として、人間がやる部分としてはVercelやCloudflare、Supabaseのアカウント作成程度で、コードは全てRooCodeに指示して作成していました。
Webアプリケーションの概要
お気に入りのお店を記録・管理できるWebアプリケーションで、できることは以下の通りでシンプルなものです。
- お店の情報を登録できる
- 一覧ページで登録したお店の一覧が見れる
- 詳細ページで登録したお店の詳細が見れ、編集・削除ができる
悩んだ経緯
このアプリケーションの開発中、一覧ページや詳細ページのデータ取得にはD1へのクエリを毎回発行していました。しかし、実行結果は変わらないことが多いため、Cloudflare Workers KVを利用してキャッシュすることで負荷を軽減できると考えました。そこで開発環境にCloudflare Workers KVを導入し、データのキャッシュ機能を実装。ローカル環境ではback/.wrangler/state/v3
にD1やR2、KVのデータが保存されるため、Edge特有のCold Startを感じることはありませんでした。
ところが、本番環境にデプロイしてページをアクセスすると、初回アクセス時のみREST APIからのデータ取得に1秒ほどかかることに気づきました。Cloudflare Workersには「High performance runtime with no cold starts」という特長があるはずなのに、なぜ初回アクセスだけ遅延が発生するのか疑問に感じた、というのがことの経緯です。
念のため測定
テストコードでAPIレスポンス時間を計測してみました。
(async () => {
try {
// 開始時刻を取得
const startTime = performance.now();
// リクエストを送信
const response = await fetch("https://xxxxxxxxxxx/api/shops?page=1&perPage=12", {
headers: {
accept: "application/json, text/plain, */*",
authorization: "xxxxxxxxxxx",
},
method: "GET",
});
// レスポンスをJSONとして取得
const data = await response.json();
// 終了時刻を取得
const endTime = performance.now();
// 所要時間を計算
const elapsedTime = endTime - startTime;
// 結果をコンソールに出力
console.log(`リクエストにかかった時間: ${elapsedTime.toFixed(2)} ms`);
} catch (error) {
console.error("Fetchエラー:", error);
}
})();
結果は以下の通りです。
- Cold Startが発生した際のレスポンス時間
$ node test.js
リクエストにかかった時間: 1350.49 ms
- Cold Startが発生しなかった際のレスポンス時間
$ node test.js
リクエストにかかった時間: 171.91 ms
- 約50秒放置するとWorkers KVがスピンダウンし、その後のリクエスト時に遅延発生することを確認
- Wokers PlanをFreeからPaidに変更しても同様であることを確認
答えあわせ
色々、調べたのですが、灯台下暗しで公式にしっかりと記載がありました。 なぜ、Cloudflare Workers KVの初回アクセスが遅いのか
Initial reads from a location do not have a cached value. Data must be read from the nearest regional tier, followed by a central tier, degrading finally to the central stores for a truly cold global read. While the first access is slow globally, subsequent requests are faster, especially if requests are concentrated in a single region.
つまり、初回アクセス時はEdgeにキャッシュされていないため、ストレージからデータを取得する必要があり、Cold Startが発生し低速となる。以降はEdgeにキャッシュされるため高速に読み取りが可能とのことでした。
また、続きで下記のようにも記載がありました。
KV is optimized for high-read applications. It stores data centrally and uses a hybrid push/pull-based replication to store data in cache. KV is suitable for use cases where you need to write relatively infrequently, but read quickly and frequently. Infrequently read values are pulled from other data centers or the central stores, while more popular values are cached in the data centers they are requested from.
つまり、Cloudflare Workers KVは読み取り処理が多いアプリケーション向けに最適化されており、今回作成したWebアプリケーションのようなアクセス頻度の少ないケースには適していないということでした。
今回のまとめと所感
- 結論は冒頭に記載した通りです
- Cloudflare Workersの利点として挙げられている
High performance runtime with no cold starts
という記述をKVに対しても同様だと思い込んでいたための誤解でした - コーディングはRooCodeが適切にやってくれるが、それを指示する人間が正しい情報を持っていないと問題が発生することを痛感しました。(指示の与え方だったりコンテキストの渡し方にずれがあったのかなと思います)
参考
- 公式
- Cloudflare Community
- Zenn