章と記事の一覧
読むストレージ
状態の置き場所を選ぶ
一貫性・サイズ・課金から KV / D1 / R2 / Durable Objects を選ぶ
Cloudflare Workers の 1 つのインスタンスは、複数のリクエストを同時に処理することがある。どのリクエストが同じインスタンスに届くかは保証されず、インスタンスもいつ退避されるか分からない。そのため、メモリ上の変数は状態の置き場として当てにできず、データは外部のストレージ層に任せることになる。
問題は「どのストレージを選ぶか」である。この選択を誤ると、直前の書き込みが読み取れない幽霊データ現象や、インデックス未設定によるクエリ課金の爆発、単一インスタンスへの過負荷によるボトルネックを招く。選択の判断軸は、一貫性モデル・データサイズ・課金トリガー の 3 点に集約される。
一貫性モデルによる第一選別
| ストレージ | 一貫性レベル | 最適なユースケース | 危険な誤用 |
|---|---|---|---|
| Workers KV | 結果整合性(他のロケーションへの反映に 60 秒以上かかることがある) | 設定値、機能フラグ、URL リダイレクト表 | 厳密なカウンタ、残高、購入直後のセッション |
| D1 | 既定は単一のプライマリ(レプリカ読み取りは有効化と Sessions API が必要) | 構造化データ、リレーション検索、集計 | 大きなバイナリの格納(1 行 2MB が上限) |
| Cloudflare R2 | 強整合性(オブジェクト単位) | 画像、動画、ログ、バックアップ | 数キロバイトの細粒度な頻繁更新 |
| Durable Objects | 単一インスタンス、ストレージは強い一貫性(ストレージ以外の I/O の待機中は割り込みあり) | チャットルーム、チケット在庫、分散ロック | 全リクエストの無差別な集約 |
| Hyperdrive | 接続プールと読み取りクエリのキャッシュ(既定で有効。max_age 既定 60 秒の間は古い結果が返りうる) | PostgreSQL / MySQL との高速通信 | 書き込み直後の読み取り(キャッシュ有効時) |
「世界で唯一つの最新の値を競合なしに更新したい」場合は Durable Objects を、リレーションや集計が必要な場合は D1 を選ぶ。安易に KV へカウンタを置けば、別々のロケーションからの同時書き込みが互いを上書きし(後勝ち)、加算が失われる。
サイズ制約と課金構造の落とし穴
- Workers KV: 1 キーあたり 25MB。読み取りは 100 万回あたり 0.5 ドルだが、書き込みは 100 万回あたり 5 ドルと単価が高いため、更新頻度の高い設計は避ける。
- D1: 発行したクエリ数ではなく、読み取った(走査した)行数と書き込んだ行数で課金される。
CREATE INDEXのないWHEREクエリは全行を走査して読み取り行数を押し上げる。一方、インデックスは書き込みのたびに書き込み行数を 1 つ増やす。 - Cloudflare R2: 保存容量と操作回数(Class A / Class B)で課金され、R2 から直接の下りデータ転送(Egress)は無料である。ただし読み取りは Class B 操作として課金され、Infrequent Access クラスにはデータ取得料金もかかる。配信量の大きい静的ファイルは、操作回数まで見積もってから R2 に置く。
- Durable Objects: リクエスト数と実行時間(実際の経過時間を 128MB 固定で GB 秒に換算)の従量制で、SQLite ストレージは読み取り行数・書き込み行数・保存容量でも課金される。ハイバネーション可能な状態でアイドルの間は、時間課金は発生しない。
代表的なアンチパターン
- セッション保存に KV を採用し、ログイン直後にリダイレクト先で検証する: リダイレクト先が別のロケーションで処理されると、キャッシュが切れるまで古い値(またはキーなし)が返ることがあり、認証に失敗する。直後の状態遷移は暗号化 Cookie などのステートレスな手段と組み合わせる。
- D1 のカラムに画像や PDF のバイナリを直接格納する: 1 行(1 BLOB)の上限は 2MB で、画像や PDF は超えやすい。データベース全体の上限も 10GB(無料プランは 500MB)である。なお、読み取り行数の課金は行のサイズに左右されない(1KB の行も 100KB の行も 1 行)。バイナリ実体は R2 に置き、D1 にはオブジェクトキーだけを記録する。
- 全てのトラフィックを 1 つの Durable Object インスタンスへ集中させる: 直列化機構が裏目に出て、世界中からのリクエストが単一ノードで順番待ちを起こし、レイテンシが急激に悪化する。テナント単位やユーザー単位で ID を細かく分散させなければならない。
堅牢な組み合わせパターン
- R2(実体ファイル)+ D1(メタデータ索引): 画像やドキュメントの本体は転送無料の R2 に預け、タグや更新日時、所有者 ID は D1 でインデックス検索する。
- Durable Objects(整合性の関所)+ Queues(非同期消化): 注文の引き当てや在庫の減算は DO で直列化して整合性を担保し、時間のかかる決済処理やメール配信は Queues に任せる。