データ ストア エントリの作成時にクライアントの再試行を処理するための戦略を考え出す必要があります。
- クライアントは、データベースに新しいエントリを作成する要求を送信します
- サーバーはエントリの作成を実行し、成功応答を準備します
- リクエストが処理されなかったとクライアントに信じ込ませる何らかのエラーが発生します (パケット損失など)。
- クライアントは、データベースに新しいエントリを作成するために同じ要求を再度送信します
- サーバーは再試行を検出し、別のデータストア エントリを作成せずに元の応答を再作成して送信します
- クライアントが返信を受け取る
- 誰もが満足し、データベースには 1 つのエントリしか作成されませんでした
制限が 1 つあります。サーバーはステートレスです。クライアントにセッション情報はありません。
私の現在の考えは次のとおりです。
- すべての create-request に、保証されたグローバルに一意の ID をタグ付けします (質問にはあまり関係ありませんが、作成方法は次のとおりです)。
- データ ストア (および memcache) を使用して、サーバー インスタンスが読み込まれると、単調に増加する一意の ID をすべてのサーバー インスタンスに割り当てます (これをSIと呼びましょう) 。
- クライアントが開始ページを要求すると、要求を処理したインスタンスは、単調に増加する一意のページ ロード ID ( PL ) を生成し、 SI.PLをページ コンテンツと共にクライアントに送信します。
- create-request ごとに、クライアントは単調に増加する一意の request-id ( RI ) を生成し、create-request とともにSI.PL.RIを送信します。
- create-request ごとに、サーバーは最初に create-tag を認識しているかどうかを確認します。
- そうでない場合は、新しいエントリを作成し、何らかの形で create-tag を一緒に保存します。
- タグがわかっている場合は、それを使用して最初に作成されたエントリを見つけ、対応する応答を再作成します。
現在考えている実装オプションとその問題点は次のとおりです。
- create-tag をエントリ内のインデックス付きプロパティとして保存します。
- サーバーがリクエストを受け取ると、クエリを使用して既存のエントリを見つける必要があります
- 問題: AppEngine のクエリは結果整合性しかないため、エントリを見逃す可能性があります
- create-tag をエントリのキーとして使用します。
- 数値がラップされない場合は一意であることが保証されているため、問題ありません (long の場合はそうではありません)。
- マイナーな不便: 将来の使用でエントリのキーの長さが増加します (不要なオーバーヘッド)。
- 重大な問題: これにより、データストアに連続したエントリ キーが生成されます。これは、格納されたデータにホット スポットが作成され、パフォーマンスに大きな影響を与える可能性があるため、絶対に回避する必要があります。
オプション 2 について私が考えている解決策の 1 つは、ホットスポットを排除する代わりに、連番を取得し、それらを一意で決定論的だがランダムに見えるシーケンスに再マッピングする何らかの式を使用することです。そのような式がどのように見えるかについてのアイデアはありますか?
それとも、全体的により良いアプローチがありますか?