Cloudflareのバースデーウィークで発表されたSQLite in Durable Objectsが面白そうだったので少し調べてみました。D1の裏で使われていた機能が一般のユーザーでも使えるようになったようです。
概要
Zero-latency SQLite storage in every Durable Object や Build a seat booking app with SQLite in Durable Objects | Cloudflare Durable Objects docs を読むとより詳細な情報が得られますが、大まかには以下のようになります
DurableObject
クラスを継承したクラスを定義して登録すると、そのクラスの中のコードはローカルマシンにストレージを持った別のV8 isolateで動く。- メソッドを呼び出すと、裏でそのDurable Object(DO)にRPC*1。
- ストレージはリージョン内の複数のデータセンターで冗長化されている。
- ストレージのインタフェースがKVストアだったのがSQLiteになりました。
良さそうなところ
SQLite と同じスレッドでユーザーコードが動く
Zero-latency SQLite storage in every Durable Objectにも書かれていますね。 N+1だけでなく、ツリーのような再帰的な構造を扱ったり、GraphQLのAPIを作るにも使えるかもしれません。 バックアップや冗長化などがマネージドなSQLiteで、ユーザーコードが同じマシンで動かせるのは大きな魅力です。
トランザクションが使える
D1ではトランザクションが使えませんでしたが、Cloudflareの開発者によるとDOsでは this.ctx.storage.transactionSync
でトランザクションを使えるようです*2(BEGIN
は利用不可)。
試した限りではINSERT OR ROLLBACK
のような文は使えなくて、 INSERT (OR ABORT)
を使ってunique 制約に違反するなど、JavaScript 側の例外でロールバックできるようです。トランザクション内でawait
もできませんが、十分に実用できそうです。
以前はストアドプロシージャーを使ってトランザクションを実現するといった話もありましたが*3、SQLite in DOsの方が柔軟でよさそうですね。
多数のデータベースを扱える
D1は1つのbindingが1つのデータベースで、1つのWorkersには5000個くらいしかbindingできませんでした*4。 DOsは1つのbindingが1つのネームスペースで、ネームスペースの中にはいくつでもDO(=データベース)を作れます。 それぞれのDOが別のV8 isolateになるので、適切にパーティショニングできれば書き込みもスケールしそうです。
活かせそうな応用例としては
- モバイルアプリ用のユーザーデータを保存する。シングルプレイ寄りのゲームとか、ユーザーごとの閲覧履歴をサーバーと同期するとか。
- SNSのようなタイムラインをユーザーごとにDOを用意して、GAしたWorkers Queuesでfan outするのも面白そうです。
地理的にユーザーの近くにDOが作られそうなのもいいですね。
また読み込み性能のスケールのために read replica? のような機能の開発も進行中のようです*5。
1行のサイズ制限がD1の2倍
ドキュメントのミスでなければD1は1MBですがDOsは2MB *6*7
おわり
機会があれば使ってみたいですね。Drizzle ORMは割と早く対応してくれそうな気がしてます。
*1:https://developers.cloudflare.com/workers/runtime-apis/rpc
*2:https://discord.com/channels/595317990191398933/773219443911819284/1292483777557172316
*3:https://blog.cloudflare.com/whats-new-with-d1/
*4:https://developers.cloudflare.com/d1/platform/limits/
*5:https://discord.com/channels/595317990191398933/773219443911819284/1288889128074612832
*6:https://developers.cloudflare.com/durable-objects/platform/limits/