Durable Objects は、Cloudflare Workers の上に構築され、グローバルインフラネットワーク上の複数拠点にまたがります。 各 Durable Object インスタンスは、リクエストをまたいで残る永続ストレージ、インメモリ状態、シングルスレッド実行を持ち、特定リージョンに配置できます。
1 つの Durable Object インスタンスには、一定の 性能とストレージの上限 があります。 そのため、単一インスタンスの上限に縛られずにアプリケーションをスケールするには、アプリケーションデータをできるだけシャーディングし、Cloudflare のインフラ ↗ を活かして Durable Object インスタンスを世界中へ分散し、データとコンピュートの両方をユーザーの近くへ寄せます。
このドキュメントでは、コントロールプレーンとデータプレーンを分離し、機能を落とさずに性能と信頼性を高める構成パターンを説明します。
- コントロールプレーン は、リソースのメタデータを管理する管理用 API を提供します。たとえば、ユーザーが wiki を作成 / 削除する、ユーザーの wiki 一覧を取る、といった操作です。
- データプレーン は、アプリケーションの主機能を提供し、リソースデータへの操作を直接扱います。たとえば、wiki の内容の取得と更新、共同編集ドキュメントの更新です。データプレーンは意図的に単純で、扱うリクエスト量は通常はるかに大きくなります。
- マネジメントプレーン は任意の構成要素で、コントロールプレーンより高い抽象度で操作し、設定と運用を簡単にします。このドキュメントでは扱いません。適用する原則はコントロールプレーンと同じです。
このパターンでは、アプリケーションは少なくともリソースタイプごとに 1 つの Durable Object インスタンスを持ち、そのコントロールプレーン操作をすべて処理します。データプレーン操作には、アプリケーション内で作られたリソースインスタンスごとに 1 つずつ、必要な数の Durable Object インスタンスを使います。
Durable Object インスタンスは、リソースごとに 1 つずつ、数百万までスケールできます。
この構成の主な利点は、データプレーン操作(通常はコントロールプレーンよりリクエスト量が多い)を、コントロールプレーンの Durable Object を経由せず、リソースデータを持つ Durable Object インスタンスが直接扱うことです。 そのため、アプリケーションの性能と可用性は、単一の Durable Object インスタンスではなく、数千から数百万の Durable Objects に分散します。
汎用のリソースタイプ XYZ を例にします。実務では XYZ は wiki、共同編集ドキュメント、ユーザーごとのデータベース、その他のリソースタイプです。
- ロンドン(LHR)のユーザーが、リソース
XYZの作成リクエストを開始します。リクエストは最寄りの Cloudflare データセンターへルーティングされ、アプリケーション API を提供する Workers フリートが受け取ります。 - Worker コードは、タイプ
XYZのリソースを管理する、適切なコントロールプレーン Durable Object インスタンスへリクエストを送ります。Durable Object インスタンスの参照にはidFromNameを使い、名前(control-plane-xyz)で指定します。マッピングを保持しなくても、コントロールプレーン Durable Object へすぐアクセスできます。- コントロールプレーン Durable Object の配置は、最初にアクセスしたリクエストの近く、または Location Hints で明示したリージョンになります。
- コントロールプレーン Durable Object インスタンス(
control-plane-xyz)はリクエストを受け取り、すぐに別の Durable Object インスタンス(data-plane-xyz-03)をユーザーリクエストの近くに作ります(Location Hints を使用)。リソースの内容を持つ実体を、作成したユーザーの近くに置きます。 - 作成した Durable Object インスタンス(data-plane-xyz-03)に対して、カスタムのinit(...)を呼び出し、リクエスト処理の開始に必要なメタデータを渡します。 Durable Object インスタンスはこの情報をローカルストレージへ保存し、必要な初期化を行います。 以降の各リクエストに、処理に必要な情報がすべて含まれている場合、この手順は省略できます。たとえば、リクエスト URL のパスとクエリパラメータに必要な情報がすべて入っている場合です。 - Durable Object(data-plane-xyz-03)の参照にはidFromNameを使い、名前ベースのリソース識別子を使えます。 - 代わりにnewUniqueIdで参照すると、名前ではなくランダムなリソース識別子が得られます。このランダム識別子はユーザーへ返し、以降のリクエストでリソースへアクセスするときに指定してもらう必要があります。 - コントロールプレーン Durable Object インスタンス(
control-plane-xyz)は、生成した識別子(data-plane-xyz-03)をローカルストレージへ保存し、作成済みリソースの一覧 / 削除ができるようにしたうえで、Worker へ返します。 - ユーザーはリソース作成の成功レスポンスと対応する識別子を受け取り、(任意で)そのリソースへリダイレクトされます。
- ユーザーは、前の手順で返ったリソース識別子に対して API へ書き込みリクエストを送り、リソースの内容を更新します。
- Worker コードは、渡されたリソース識別子を使い、そのリソースのデータプレーン Durable Object インスタンス(
data-plane-xyz-03)を直接参照します。Durable Object インスタンスは、内容をローカルの永続ストレージへ書き込み、適切にレスポンスを返します。 - ポートランド(PDX)の別ユーザーが、以前作成したリソース(
data-plane-xyz-01)へ読み取りリクエストを送ります。 - Worker コードは、指定されたリソース識別子のデータを持つ Durable Object インスタンス(
data-plane-xyz-01)を直接参照します。Durable Object インスタンスは、ローカルストレージを読んで内容を返します。
アプリケーションのデータモデルがリソース単位でシャーディングできるなら、好きなだけスケールアウトでき、そのリソースへアクセスするユーザーの近くにデータを置けます。
必要な性能を得るために、同じパターンを必要な回数だけ適用できます。
たとえば負荷に応じて、コントロールプレーン Durable Object をさらに複数の Durable Objects へシャーディングできます。
タイプ XYZ の全リソースを 1 つの Durable Object インスタンスで扱う代わりに、リージョンごとに 1 つ置けます。
名前ベースの参照なら、対象インスタンスの指定も簡単です。
まとめると、アプリケーションのデータモデルを、自己完結した細かいリソースへシャーディングできれば、リソースごとに少なくとも 1 つの Durable Object インスタンスを割り当ててスケールアウトできます。