D1 制御プレーンの設計パターン: ホットパスから中央 DB を外す
Cloudflare 公式が公開した D1 制御プレーンの裏側から、「データ面はエッジ完結・制御面だけ中央」「Workers KV でルーティング」「ハートビートで自己修復」「利用量はキュー+事前集計」といった、マルチテナント基盤に再利用できる型を抜き出す。
どんなときに使う?
- Workers / Durable Objects で「テナント(やユーザー)ごとに DB・DO を大量に作る」基盤を組む
- クエリ経路に Postgres や単一リージョン依存を入れてしまいレイテンシ・障害面が心配
- 作成・削除・課金制限など制御系と、読み書きホットパスを分けたい
やり方(再利用できる型)
1. 面を分ける
- データ面: クエリ。できるだけエッジで完結し、中央単一リージョンを通さない
- 制御面: 作成・削除・一覧・権限。中央 Postgres 等に依存してよい
- 非同期面: 課金・分析。結果整合でキュー処理
2. ルーティングメタデータは Workers KV
DB UUID → Durable Object ID などの対応は Workers KV に載せる。キャッシュミス時だけ Hyperdrive 経由で Postgres レプリカへフォールバック。KV は「ただのキャッシュ」ではなく、中央 DB をホットパスから外す耐久ストアとして使う。
3. 作成は失敗前提・べき等・自己修復
DO 初期化 → Postgres 永続化 → KV 書き込み、の順。途中失敗で orphan DO が出ても、DO が定期 ハートビートして「Postgres に無い/削除済み」なら自分を消す。作成リトライでは UUID / DO ID を使い回さない(複数 DO が同一 DB を名乗る事故を防ぐ)。
4. 利用量制限はキューと事前集計
各 DO がストレージ使用量をキューへ出す → コンシューマが DB 行を更新 → トリガで差分ログ → 定期ジョブがアカウント単位合計を更新。読み取り時に SUM スキャンしない。Hyperdrive キャッシュのキーはアカウント ID だけにし、数百万 DB でもキャッシュが効くようにする。TTL を短くしたいクエリにはダミー列(dynamic_ttl)でキャッシュキーを時間桶に分ける技もある。
5. 分析は ClickHouse、制限フラグはエッジの KV
行数課金など分析は ClickHouse。制限超過アカウントはグローバルに速い KV(社内 Quicksilver/利用者なら Workers KV Instant 相当)にフラグを立て、DO がエッジで読んで拒否する。
注意点
- 公式ブログは Cloudflare 内部の話も含む。同じコンポーネント名をそのまま使えるとは限らないが、境界の引き方は移植できる
- Durable Objects を name でアドレスする方が簡単なケースが多い。unique ID + 外部マッピングは「名前解決の中央往復を避けたい」ときの選択
- 結果整合の制限は「反応が数秒〜数十秒遅れる」ことをプロダクト仕様として説明する