多数のアイテムを含む結果ストリームがある場合、それらを保存して、潜在的な同時実行の競合を処理します。
_public void onTriggerEvent(/* params */) {
Stream<Result> results = customThreadPool.submit(/*...complex parallel computation on multiple servers...*/).get();
List<Result> conflicts = store(results);
resolveConflictsInNewTransaction(conflicts);
}
_
store(...)
を効率的に実装する方法について、私はstuckです。 Result
は、それぞれのDBテーブルで更新する必要のあるデータを記述する2つの不変で分離されたオブジェクトで構成されています。
_@Value
public static class Result {
A a; // describes update for row in table a
B b; // describes update for row in table b
}
_
A
およびB
はそれぞれ2人のユーザーを参照します。ここで、_(u1, u2)
_はそれぞれのDBテーブルのキーです。
_@Value
public static class A {
long u1;
long u2;
// ... computed data fields ...
}
// B accordingly
_
ストリーム計算自体は同時にトリガーされる可能性があります(複数のonTriggerEvent
の並列呼び出し)がほとんど問題ありませんが、一部の結果で競合が発生する場合があります(約0.1%が競合します。たとえば、ストリームに_(53,21)
_の結果と別の呼び出しも_(53,21)
_を更新しました)。 A
やB
の競合は、操作の開始と比較すると異なるupdatedAt
フィールドによって示されます。もちろん、ここでは、すべての結果を破棄して再試行するのではなく、競合している行を解決したいだけです。
したがって、(1)競合していないすべての_Result.a
_および_Result.b
_を格納し、(2)List
のResult
sを取得するための適切なアプローチは何でしょうか。紛争中で特別な扱いが必要です。
_public List<Result> store(Stream<Result> results) {
// store all a
// store all b (ideally without using results * 2 RAM)
// do update other stuff if a and b are not in conflict and do it in the same ACID transaction as the update of the related a and b.
// return those in Conflict
}
_
各結果をアンパックせずにそれを実装し、独自のトランザクションなどでデータベースに送信するにはどうすればよいですか?理想的には、一度にすべてをDBに送信して、格納されていない(および他のものが保持されているはずの)競合のリストを取得する必要があります。私も別のアプローチを受け入れています。
必要に応じて、JPA/Hibernateを使用します。
最も簡単なのは、永続性をFIFOキューに合理化することです(多くの技術が存在しますが、一般的には「トランザクションごとに1つのエントリ」になるため、望ましいアプローチではありません)。 。
したがって、2番目のオプションでは、同時実行競合定義のロジックをデータベースの永続化アクションから別のサービスに移動します。
UserId-to-Reentrantロックのメモリ内マップのようなものを実装できます(これらの操作は、同期されたブロックと比較して、非常に高速です)。
永続化する最初の呼び出し中に、ロックがロックされます。永続化が成功すると、ロックが解放されます。その間(別のスレッドで)ロックの状態を確認し、それによってフィルターで除外するか、ロックが解放されるまで待つことができます。待機状態には注意してください。ストリームがあるため、ストリームを処理するスレッド全体が待機状態になります。
個人的には、最初の「トランザクションごとに1つのエントリ」に固執し、途中に(永続的な)メッセージングキューがあり、ロックチェック用の個別のサービスを備えています。まず、これにより、書き込み操作の同時実行を簡単に構成できます。ロックされるエントリは1つだけなので、2番目はライターで待機状態を簡単に使用できます。