1

JDO を使用して Datastore エンティティにアクセスしています。異なるプロセスが同じエンティティに並行してアクセスし、これを解決する方法がわからないため、現在問題が発生しています。

値と計算値を含むエンティティがあります: (キー、値1、値2、値3、計算)

計算は別のタスク キューで行われます。ユーザーはいつでも値を編集できます。値が更新されると、新しいタスクがキューにプッシュされ、古い計算値が上書きされます。

私が現在抱えている問題は、次のシナリオにあります。

  1. ユーザーがエンティティを作成
  2. タスクが開始されました
  3. ユーザーは最初のエントリのエラーに気付き、エンティティをすばやく更新します
  4. タスクは古いデータ (ステップ 1 から) に基づいて終了し、エンティティ全体を上書きし、新しく入力された値 (ステップ 3 から) も削除します。
  5. ユーザーが満足していない

だから私の質問:

  • 手順 4 で更新時にタスクを失敗させることはできますか? タスクをトランザクションにラップしても、結果整合性のため、すべてのケースでこの問題が解決されるわけではないようです (または、データストア トランザクションに関する私の理解が間違っている可能性があります)。
  • エンティティの単一フィールドを更新する唯一の方法は低レベルの setProperty メソッドを使用することですか?これで問題は解決しますか?
  • 上記のいずれでもない場合、このようなユースケースに対処する最善の方法は何ですか?

バックグラウンド:

現時点では、一貫性のためにパフォーマンスを犠牲にすることは気にしません。性能については後ほど。

これは私にとって初めての AppEngine アプリケーションであり、学習プロセスであったため、いくつかのベスト プラクティスは使用していません。後から考えると、自分のデータ スキーマについて、より長く、より真剣に考える必要があったことは十分承知しています。たとえば、適切な先祖関係を使用しているエンティティはありません。私はリレーショナルのバックグラウンドから来ており、それが示しています。

おそらく Objectify に移行する大規模なリファクタリングを計画していますが、それまでの間、できるだけ早く解決する必要がある緊急の問題がいくつかあります。そして、まずデータストアを完全に理解したいと思います。

4

3 に答える 3

2

GAE で書き込み競合を処理する必要があるときはいつでも、ほとんどの場合トランザクションが必要です。ただし、「トランザクションを使用する」ほど単純ではありません。

  1. まず、作業の各論理単位をトランザクションで定義できることを確認します。取引には制限があります。祖先のないクエリはなく、特定の数のエンティティ グループのみにアクセスできます。トランザクションを開始する前に、追加の作業を行う必要がある場合があります (つまり、トランザクションに参加するエンティティのキ​​ーを検索するなど)。
  2. 各作業単位がべき等であることを確認してください。これは重要です。一部の作業単位は自動的に冪等になります。たとえば、「メール アドレスを xyz に設定する」などです。一部の作業単位は自動的にはべき等ではありません。たとえば、「アカウント A からアカウント B に $5 を移動する」などです。トランザクションの開始前にエンティティを作成し、トランザクション内のエンティティを削除することで、トランザクションを冪等にすることができます。トランザクションの開始時にエンティティの存在を確認し、エンティティが削除されている場合は単純に (txn を完了して) 返します。
  3. トランザクションを実行するときConcurrentModificationExceptionは、ループ内でプロセスをキャッチして再試行します。これで、任意の txn が競合した場合、成功するまで単純に再試行します。

ここでの衝突の唯一の悪い点は、システムの速度が低下し、再試行中に労力が無駄になることです。ただし、1 秒あたり少なくとも 1 つの完了したトランザクション (XG トランザクションがある場合は少し少なくなる可能性があります) のスループットが得られます。

Objectify4 が再試行を処理します。作業単位を run() メソッドとして定義し、ofy().transact() で実行するだけです。あなたの仕事がべき等であることを確認してください。

于 2012-11-20T17:56:16.577 に答える
2

明らかに、JDO にはトランザクションの楽観的並行性チェック (ユーザーが有効にする必要があります) が付属しており、そのようなことが防止/削減されます。オプティミスティック コンカレンシーはリレーショナル データストアにも同様に適用できるため、その機能についてはご存じでしょう。

Google の JDO プラグインは明らかに低レベル API の setProperty() メソッドを使用します。ログには、どのような低レベルの呼び出しが行われたか (PUT および GET に関して) も示されます。他の API に移行しても、それだけではこのような問題は解決しません。

于 2012-11-20T10:19:50.667 に答える
1

私の見方では、タスクが最初に起動されたときから特定の値が変更されたため、最初のタスクがオブジェクトを更新しないようにすることができます。

または、オブジェクトの値をタスクリクエスト内に埋め込んで、2番目の計算タスクが一貫した値と計算されたメンバーでオブジェクトの状態を復元するようにすることもできます。

于 2012-11-20T21:16:02.000 に答える