個人で運用しているサービスでNeonを利用していたが、そこそこ値段が高くなってきたのでCloudflareのD1へ移行しました。
運用物の前提
- Cloudflare Workers上で動く配信系のキュレーションサイト/管理画面/Discord Bot(500 Server~)
移行前のざっくり構成図は↓

関連記事
モチベーション
NeonのLaunchプランで月$40~$50前後かかっていました。(Compute CU-hour課金) 大した額ではないですが、データ量に対して額が徐々に増えてきていたので、早いうちに手を打っといたほうが良いなーというところで移行を考え始めました。

移行先としてはサーバーのスタックを全てCloudflareに寄せていたこともあり、Internalで完結できるD1を第一候補で考えました。
D1のWorkers Paidプランは月次無料枠で25 billion rows read・50 million rows written・5 GB storageです。
Neonを運用していたときはの時のDBはtup_returnedが1年で20億程度だったので、雑に平均して550万行/日~くらいのD1でのスキャン量になりそうかなという見積もりでした。
自分の規模なら工夫すればWorker Paidのプランであれば実質無料で利用できそうです(???)
D1の制約と対応
| 項目 | Workers Paid |
|---|---|
| Max database size | 10 GB(ハードリミット) |
| Max bound parameters per query | 100 |
| Queries per Worker invocation | 1,000 |
| Max SQL query duration | 30 sec |
物理構成と分散配置
D1は単一プライマリ + 非同期レプリカの構成で、プライマリの物理リージョンはcreate時に決まり、以後は動かません。候補は6リージョン(wnam / enam / weur / eeur / apac / oc)で、自分は主要ユーザーが日本なのでapacを指定しました。
ただしapacを指定したからといって正確にその範囲に置かれるわけではなく、location hintは候補リージョンへのbest-effortフォールバックという扱いになるので本当にapacにあるのかはわかりません。
Providing a location hint does not guarantee that D1 runs in your preferred location. Instead, it will run in the nearest possible location (by latency) to your preference.
10 GBのハードリミットがあるので、公式はDBを分割して利用するように推奨されています。
D1 is designed for horizontal scale out across multiple, smaller (10 GB) databases, such as per-user, per-tenant or per-entity databases.
なので今回はドメインごとにD1のDatabaseを複数に分離してテーブルなどの再設計を行いました。(省略)
D1移行で対応したこと
- 1DBあたり10 GBのハードリミット
この制約は結構でかいので、日時で増えていくデータに対してはretention policyを定めて運用をするようにしました。(D1は参照頻度の高い直近分だけ持たせ他はR2へ逃す感じ)
ちなみに無料枠は5 GB、超過分は$0.75/GB-moの従量課金で、これは10 GBのハードリミットとは別軸。10 GB未満であれば追加課金だけで済みます。
- bound parameters100個上限
SQLite一般のSQLITE_MAX_VARIABLE_NUMBERは999〜32766なので、数千行規模のbatch insertを感覚で書いていたところtoo many SQL variables相当のエラーで落ちたので、アプリでよしなに分割してInsertをしています。
- その他
- Miniflare等を活用し事前にワークフローレベルのIntegration Testを構築し、D1に切り替えたとて振る舞いが変わらないことを検証
- 対話型トランザクションはD1にないのでbatchに寄せる
- UUID採番はアプリ側、DBトリガー依存は排除する
- パフォーマンス劣化が起きないかの確認(そもそもNeonがシンガポールで運用していて対して速度出ていなかったのでそれより悪くはならんやろという前提の元、
ザル計測で済ませた、同等以上のパフォーマンスはでてるはず、割と最近)- 一応Read ReplicaもBetaであるらしいが今回は使わず、既存のKVを生かしたStale許容な感じのRead戦略にしている。
移行後Hyperdriveが不要になり、アプリ側はD1Databasebinding 1本で読み書き両用の構成に変わりました。コストは月$50前後からWorkers Paid $5/moの枠内に収まっています。