言語を切り替える
テーマを切り替える

Workersの無料枠が足りない?10万リクエストを1ヶ月持たせる7つの最適化術

はじめに

先月、R2ストレージと組み合わせてWorkersで画像ホスティングサービスを作りました。完璧だと思っていたのですが、3日も経たないうちにCloudflareから「無料枠の上限に近づいています」というメールが届きました。

「えっ、毎日10万回も使えるんじゃないの?」と驚きました。個人的な画像置き場にそんなアクセスがあるはずがありません。Analyticsを確認すると、なんと1日平均12万リクエスト。目を疑いました。アップロードした画像は数十枚程度なのに。

その後、ドキュメントを読み込み、コミュニティの議論を漁って、Workersの課金システムの「落とし穴」をようやく理解しました。サブリクエスト、KV読み込み、キャッシュヒット…これら全てが「隠れて」枠を消費していたのです。

でも良いニュースがあります。ルールを理解して最適化を行った結果、日次リクエストを12万から3万まで減らすことができました。今では無料枠内で十分収まり、30%ほどの余裕さえあります。今日は、毎月5ドルの有料プラン料金を節約するための実践的なテクニックをシェアします。

騙されないで!Workersの「10万回」の真実

正直、Cloudflareのドキュメントにある「1日10万リクエスト」という表記は誤解を招きやすいです。私は最初、「自分のWorkerが10万回アクセスされるまで大丈夫」だと思っていました。でも計算方法は違います。

真実1:サブリクエストは個別課金されないが、数に制限がある
Worker内で fetch() を使って他のAPIを叩いたり、R2を読んだり、KVを検索したりするのを「サブリクエスト」と呼びます。良い点は、これらが個別に課金対象にならないこと。悪い点は、無料プランでは1つのリクエストにつき50回までという制限があることです(有料プランは1000回)。
例えば、ユーザーがあなたのサイトにアクセス(課金対象1回)し、WorkerがKVで権限確認(サブリクエスト1回)、R2から画像取得(サブリクエスト1回)をした場合、サブリクエストは2回ですが、課金カウントは1回です。
しかし、1回のリクエストで10個のAPIを叩くようなサービスを作ると、無料プランの「50回制限」にあっという間に引っかかります。

真実2:10万回はアカウント全体の制限
ここが一番の落とし穴です。負荷分散のためにWorkerを複数作っても無駄です。10万回はアカウント全体の制限です。10個のWorkerを作っても、合計で10万回までです。
制限を回避するには、有料プランにするか、リクエスト数を最適化するしかありません。

真実3:KV読み書き、Cache API操作もリクエスト消費に関わる
これが見落とされがちですが、Workerが KV.get() するたびに、サブリクエストとしてはカウントされなくても、リクエスト数としてカウントされる場合があります(※訳注:Cloudflareの仕様変更により、KV操作自体は別枠の無料枠がありますが、Worker自体の起動回数とは別に、KVの制限も気にする必要があります。文脈的には「無駄な処理がWorkerの実行時間を伸ばしたり、関連するリクエストを増やす」ことを指していると思われますが、原文のニュアンスを尊重します)。
また、Cache APIの match()put() 操作自体にもコストがかかります。

初心者がハマる3つの罠
私がリクエスト数を爆発させた原因はこれらでした:

  1. 罠1:リバースプロキシが毎回サブリクエストを投げ、キャッシュしていない
    API中継サービスを作った際、毎回オリジンAPIに fetch() していました。キャッシュを使わなかったため、ユーザーのリクエスト数だけバックエンドへの通信が発生していました。Cache APIを導入してヒット率80%にしたら、リクエスト数は半減しました。
  2. 罠2:KVを頻繁に読み込み、cacheTtlを知らない
    画像サービスで、画像ごとに KV.get() で権限チェックをしていました。cacheTtl パラメータでエッジにデータをキャッシュできることを知らず、毎回KVを叩いていました。cacheTtl: 600(10分)に設定したら、KV読み込みが70%減りました。
  3. 罠3:リダイレクトチェーンの各ステップがカウントされる
    短縮URLサービスで 302 リダイレクトを使っていました。A→B→C→目標というリダイレクトチェーンが発生すると、それぞれがリクエストとしてカウントされることがありました。直接最終アドレスを返すようにして解決しました。

これらの罠が、10万回を12万回に押し上げていた原因です。

無料枠を1ヶ月持たせる7つの最適化テクニック

ルールが分かったところで、私が実践して効果があった7つのテクニックを紹介します。

テクニック1:キャッシュを活用し、重複リクエストを80%削減
これが最も即効性があります。多くのWorkerプロジェクトは毎回リアルタイム計算する必要はありません。結果をキャッシュしましょう。
最適化前は、画像アクセスのたびに「検証→R2読み込み→返却」をしていました。Cache API導入後は:

const cache = caches.default;
const cacheKey = new Request(request.url, request);
// キャッシュ確認
let response = await cache.match(cacheKey);
if (response) {
  return response; // キャッシュヒット、即リターン
}
// キャッシュミス、処理実行
response = await handleRequest(request);
// キャッシュ設定(静的画像は1日)
response = new Response(response.body, {
  ...response,
  headers: {
    ...response.headers,
    'Cache-Control': 'public, max-age=86400',
  },
});
await cache.put(cacheKey, response.clone());
return response;

これだけでキャッシュヒット率が85%になりました。12万回のリクエストのうち、実際にWorkerのロジックが走るのは1.8万回だけになり、10.2万回分を節約できました。

85%
キャッシュヒット率向上
75%
リクエスト削減
12万→3万回
85%
キャッシュヒット
0%から大幅改善
$60
年間節約額
有料プラン回避

テクニック2:KV最適化の3原則
KVは便利ですが、リクエスト消費の主犯になりがちです。

  1. cacheTtl パラメータを使う
    KVはデフォルトでエッジに60秒キャッシュされます。更新頻度が低いなら、これを伸ばしましょう。
    // 最適化後(10分キャッシュ)
    const value = await KV.get('key', { cacheTtl: 600 });
    私は権限データを30分更新(cacheTtl: 1800)にして、読み込みを70%減らしました。
  2. Cache APIでKV結果をキャッシュ
    設定ファイルやブラックリストなど、めったに変わらないデータはWorker層でさらにキャッシュします。
    const cacheKey = `kv-cache:${key}`;
    let cached = await caches.default.match(cacheKey);
    if (!cached) {
      const value = await KV.get(key);
      cached = new Response(value);
      await caches.default.put(cacheKey, cached.clone());
    }
    return cached.text();
  3. waitUntil で非同期書き込み
    書き込み完了を待つ必要がない場合、waitUntil を使ってレスポンスをブロックしないようにします。
    event.waitUntil(KV.put('key', 'value'));
    return new Response('OK');

これらで、日次3万回のKV操作を8000回まで減らしました。

テクニック3:不要なサブリクエストを減らす
5つの外部APIを叩くサービスがあった際、以下のように改善しました:

  • 高頻度APIは5分キャッシュ
  • 低頻度APIはKVに24時間保存
  • 可能ならデータをR2に事前処理して保存
    これで80%のリクエストでサブリクエストが発生しなくなりました。

テクニック4:Request.cache でキャッシュ挙動を制御
2024年11月に追加された Request.cache プロパティを使います:

// キャッシュをスキップ(重要データ向け)
const response = await fetch(url, { cache: 'no-store' });
// デフォルト戦略を使用
const response = await fetch(url, { cache: 'default' });

プライベートな画像は no-store でCDNキャッシュを防ぎ、公開画像は default で自動最適化させました。

テクニック5:リダイレクトチェーンの最適化
Workerが 302301 を返す場合、そのリダイレクト先へのアクセスもクライアント側で新たなリクエストとなります。
短縮URLサービスでは:

// 最適化前:302リダイレクト
return Response.redirect(targetUrl, 302);

最適化後(状況による):
リダイレクト先が固定なら、クライアントにキャッシュさせるか、あるいはWorker内で fetch して内容を直接返す(プロキシする)ことで、ユーザー側のリクエスト回数を減らす戦略も考えられます(ただしこれはWorkerの実行時間とトレードオフです)。

テクニック6:リクエスト分布を監視し、「金食い虫」を見つける
無料のAnalyticsは必ず使いましょう。

  • どのパスが一番アクセスされているか?
  • どのパスのキャッシュヒット率が低いか?
  • どのパスが遅いか?
    私は /api/status というヘルスチェックAPIが監視サービスから毎分100回呼ばれており、全体の15%を占めていることに気づきました。ここに60秒のキャッシュを入れただけで、日次1.5万回節約できました。

テクニック7:非緊急タスクはCron Triggersへ
統計集計などをリアルタイムで行う必要はありません。

  • アクセス時はメモリ内カウントのみ(KV書かない)
  • Cron Triggerで1時間に1回まとめてKVに書き込み
    これで頻繁なKV書き込みを、1時間1回のバッチ処理にできました。

実戦例:画像ホスティングの日次リクエスト 12万→3万

プロジェクト背景

  • Cloudflare Workers + R2 + KV
  • 1日約2000枚の画像アクセス(実ユーザー数)
  • 3日目で日次12万リクエスト警告

問題点

  1. 毎回KVチェック: 2000回のアクセス全てでメタデータ確認(KV get)。
  2. ブラウザキャッシュなし: Cache-Control ヘッダーがなく、リロードのたびにリクエスト発生。
  3. サムネイルリアルタイム生成: 一覧表示で30枚の画像を毎回クロップ処理。

最適化ステップ

  1. KVキャッシュ: cacheTtl: 600 を設定。KV読み込み 2000回→300回(-85%)。
  2. ブラウザキャッシュ: レスポンスに Cache-Control: public, max-age=86400 を追加。重複リクエスト減で12万→4.8万。
  3. サムネイル事前生成: アップロード時に生成してR2に保存。読み込み時の処理負荷ゼロへ。4.8万→3.2万。
  4. Workerキャッシュ: Cache API導入。ヒット率78%で最終的に日次3万回で安定。

結果

指標最適化前最適化後変化
日次リクエスト12万3.2万-73%
KV読み込み2000300-85%
キャッシュ率0%78%+78%
コスト超過20%余裕70%年$60節約

課金するか、最適化するか?

課金すべきケース(月5ドル)

  1. 最適化しても日次10万を超える: ビジネスが成長している証拠です。素直に払いましょう。
  2. 大量のサブリクエストが必要: クローラーや複雑なAPIゲートウェイなど、1回の処理で多数の通信が必要な場合。
  3. 商用プロジェクト: SLA(稼働保証)やサポートが必要です。

最適化で粘るべきケース

  1. 個人・学習用プロジェクト: スキルアップも兼ねて限界までチューニングしましょう。
  2. 「金食い虫」が明確: 特定の無駄な処理がリクエストを食っている場合。

結論

Workersの10万回制限は、工夫次第でかなり「持ち」ます。

  1. Analyticsでボトルネックを特定する。
  2. キャッシュとKV最適化を行う(効果大)。
  3. 罠(サブリクエスト、TTL設定忘れ)を避ける。
  4. 7つのテクニックを組み合わせる。

Cloudflareは素晴らしいプラットフォームですが、無料枠を利用するなら「お行儀よく」使うことが大切です。最適化はリソースの有効活用そのものです。この記事が、あなたの5ドルを救う手助けになれば幸いです。

Cloudflare Workers無料枠最適化完全ガイド

課金ルールの理解から7つの実践テクニック、実例による削減効果まで

⏱️ Estimated time: 2 hr

  1. 1

    Step1: 課金ルールの理解

    サブリクエストの数制限、アカウント全体での10万回制限、KV/Cache操作もコストになる点を理解する。
  2. 2

    Step2: キャッシュ戦略の実装

    Cache APIを使って重複リクエストを削減。ブラウザキャッシュ(Cache-Control)も適切に設定する。
  3. 3

    Step3: KV操作の最適化

    cacheTtlパラメータでエッジキャッシュを活用。頻繁な書き込みを避け、読み込みをバッチ化する。
  4. 4

    Step4: 不要な処理の削減

    サブリクエストを減らし、ヘルスケックなどの非本質的なリクエストには強力なキャッシュをかける。非同期タスクはCron Triggersへ。

FAQ

Workersの「10万回」はどう計算されますか?
アカウント全体のWorkerへのリクエスト総数です。サブリクエスト(内部でのAPI呼び出し)は数に含まれませんが、1リクエストあたりの実行回数に制限(無料版は50回)があります。KVの操作などは場合によってリクエスト数や制限に影響します。
いつ有料プランにアップグレードすべきですか?
最適化しても恒常的に日次10万回を超える場合、または大量のサブリクエスト(1回で50回以上)が必要な場合、あるいは商用利用でSLAが必要な場合です。
キャッシュを使うとデータが古くなりませんか?
はい、トレードオフです。しかし「cacheTtl」や「max-age」を適切に設定(例:重要データは1分、画像は1日)することで、鮮度とパフォーマンスのバランスを取ることができます。

5 min read · 公開日: 2025年12月1日 · 更新日: 2026年1月22日

コメント

GitHubアカウントでログインしてコメントできます

関連記事