バックグラウンド::::
Java 用の Google アプリ エンジン (GAE) を使用しています。大きなテーブルの長所と短所に対応するデータ モデルの設計に苦労しています。これらは以前の 2 つの関連記事です。
ほとんどのクライアント要求が 1 つのクエリだけで処理できるように、非正規化されたプロパティがエンティティに追加された完全に正規化されたバックボーンを暫定的に決定しました。
私は、完全に正規化されたバックボーンは次のようになると考えています。
- 非正規化で間違いをコーディングした場合、データの整合性を維持するのに役立ちます
- クライアントの観点から 1 回の操作で書き込みを有効にする
- データに対するあらゆるタイプの予期しないクエリを許可します (待機する意思がある場合)。
非正規化されたデータは次のようになります。
- ほとんどのクライアント要求を非常に高速に処理できるようにする
基本的な非正規化手法:::
「ファンアウト」と呼ばれる手法を説明するアプリ エンジンのビデオを見ました。アイデアは、正規化されたデータへの迅速な書き込みを行い、タスク キューを使用して、クライアントを待たせることなく舞台裏で非正規化を完了することです。参照用にここにビデオを含めましたが、その長さは 1 時間であり、この質問を理解するために見る必要はありません: http://code.google.com/events/io/2010/sessions/high-throughput -data-pipelines-appengine.html
この「ファンアウト」手法を使用すると、クライアントが一部のデータを変更するたびに、アプリケーションは 1 回のクイック書き込みで正規化されたモデルを更新し、非正規化命令をタスク キューに送信するため、クライアントは待機する必要がなくなります。それらも完了する必要があります。
問題:::
タスク キューを使用してデータの非正規化バージョンを更新する際の問題は、タスク キューがそのデータの非正規化を完了する前に、変更したばかりのデータに対してクライアントが読み取り要求を行う可能性があることです。これにより、最近の要求と一致しない古いデータがクライアントに提供され、クライアントが混乱し、アプリケーションにバグがあるように見えます。
解決策として、URLFetch を介してアプリケーション内の他の URL への非同期呼び出しを介して、非正規化操作を並行して展開することを提案します。http://code.google.com/appengine/docs/java/urlfetch/ アプリケーションは、すべてのクライアント要求に応答する前に、非同期呼び出しが完了していました。
たとえば、「予定」エンティティと「顧客」エンティティがあるとします。各予定には、誰が予定されているかについての顧客情報の非正規化されたコピーが含まれます。顧客が名前を変更した場合、アプリケーションは 30 回の非同期呼び出しを行います。影響を受ける各予定リソースに 1 つずつ、それぞれの顧客の名前のコピーを変更します。
理論的には、これはすべて並行して実行できます。この情報はすべて、データストアに 1 回または 2 回の書き込みを行うのにかかるおおよその時間で更新できます。非正規化が完了した後、タイムリーな応答をクライアントに行うことができ、クライアントが不適合なデータにさらされる可能性を排除できました。
これに関する最大の潜在的な問題は、アプリケーションが一度に 10 を超える非同期リクエスト呼び出しを実行できないことです (ここに文書化されています): http://code.google.com/appengine/docs/java/urlfetch/overview .html )。
提案された非正規化手法 (再帰的非同期ファンアウト):::
私が提案する解決策は、非正規化命令を別のリソースに送信して、命令を再帰的に同じサイズの小さなチャンクに分割し、各チャンク内の命令の数が完全に実行できるほど小さくなるまで、小さなチャンクをパラメーターとして自分自身を呼び出すことです。たとえば、30 件の予定が関連付けられている顧客が名前のスペルを変更したとします。非正規化リソースを呼び出して、30 件の予定すべてを更新するように指示します。次に、これらの命令を 3 つの命令の 10 セットに分割し、3 つの命令の各セットで独自の URL に対して 10 の非同期要求を作成します。命令セットが 10 未満になると、リソースは各命令に従って完全に非同期要求を作成します。
このアプローチに関する私の懸念は次のとおりです。
- アプリ エンジンのルールを回避しようとしていると解釈される可能性があり、問題が発生する可能性があります。(URLがそれ自体を呼び出すことさえ許可されていないため、実際には、相互に呼び出す再帰を処理する2つのURLリソースが必要です)
- これは複雑で、潜在的な障害点が複数あります。
このアプローチに関する意見をいただければ幸いです。