web-dev-qa-db-ja.com

分散システムでのエラー処理

これは、Javaアプリケーションでの2つの分散コンポーネントの一般的なシーケンスです。

1  A sends request to B
2      B starts some job J in parallel thread
3      B returns response to A
4  A accepts response
5      Job finishes after some time
6      Job sends information to A
7  A receives response from a Job and updates

これは、すべてが機能すると想定した場合の理想的なシナリオです。もちろん、実際の生活は失敗に満ちています。たとえば、最悪のケースの1つは、ネットワークが原因で#6が失敗した場合です。ジョブは正しく実行されましたが、Aはそれについて何も認識していません。

このシステムのエラーを管理する方法についての軽量なアプローチを探しています。 たくさんのコンポーネントがあるので、エラー処理のためにそれらをすべてクラスター化しても意味がありません。次に、同じ理由で各コンポーネントに再度インストールされる分散メモリ/リポジトリの使用を取りやめました。

私の考えは、Bに1つのabsolute状態を持ち、Aに永続的な状態を決して持たないという方向に向かっています。これは、次のことを意味します。

  • #1の前に、ワークユニット、つまりchangeが始まろうとしていることをAにマークします
  • Bのみがこの状態のマークを解除できます。
  • Aは、いつでもBに関する情報を取得して、状態を更新できます。
  • Aで同じユニットの新しいchangeを呼び出すことはできません。

どう思いますか?この種のシステムのエラーを緩和する軽量の方法はありますか?

8
igor

Aの永続的なログに追加するだけで十分です。これは、再起動やネットワークパーティションに対処して、最終的な一貫性を実現したり、破損を通知してそのような収束を防ぎます。償却 グループコミット を使用すると、ログエントリを永続化するための書き込みが1回未満で済みます。

あなたは、Bにマークのない状態の責任を負わせるよう提案しました。同意しません。 Aだけが新しい作業を認識し、Aだけがそれを追跡し、タイムアウトなどのエラーを報告する必要があります。 Bはべき等メッセージをAに送信し、Aは状態を更新し、必要に応じて間隔を置いて再クエリします。

ステップ0で、Aは新しい要求を認識してログに記録します。これは、Aが後で期限までに実行しなければならない義務を構成します。Aは、要求の処理が完了したことをAが知るまで、後続のステップを継続的に実行し、繰り返します。

一部のリクエストは他のリクエストよりも長くなります。処理時間の見積もりはAとBで利用できるようになりますが、おそらく処理が進むにつれて修正されます。このような推定はAにフィードバックされる可能性があるため、誤検知タイムアウトが発生することはめったにありません。 「まだ機能している、まだ機能している」というキープアライブメッセージと考えてください。

2
J_H

プッシュ戦略の代わりにプルを採用します。各パーツに他のパーツから変更をプルさせ、独自のレコードを更新します。

  • AはBがすべきことをキューに記録する
  • BはAのキューからプルして作業を行います
  • Bはキューに行ったことをログに記録します
  • AはBのキューからプルして、ジョブの結果を知りました

(私はWordキューを使用していますが、ログやトピックを代用することもできます。)

キューをサービスにベイクするか、個別のメッセージブローカーを用意できます。サービスに組み込まれた実装は、GET /jobrequests?from=<timestamp>(Bが最後に処理されたジョブリクエストのタイムスタンプを追跡する)と同じくらい簡単です。

このようなアーキテクチャのトリッキーな部分は、少なくとも1回のセマンティクスと最低1回のセマンティクスを決定することです。具体的には、Bがキューからアイテムをプルし、実行中にクラッシュした場合、どうなりますか? 2つの可能性があり、どちらが最適かは、ユースケースによって異なります。

  • At-least-once:Bは、アクションの完了後に到達したキュー内のポイントのみをコミットします。アクションが2回実行されるリスクがあります。べき等になるようにアクションを設計する場合、このアプローチを使用して1回限りの動作を実現できます。 (kafkaを使用します。)
  • 最大で1回:Bは、すべてのキューアイテムを1回だけ消費します。実行中にクラッシュした場合、アイテムは実行されません。

このアプローチの利点:

  • キューを消費するサービスは、キュープッシュが発生するために稼働している必要はありません。これは、Aが作業している間にBを再起動するか、Bが作業している間にAを再起動することが自由であることを意味します。バックグラウンドサービスの冗長ホスティングは、全体的な応答時間を確保するためにのみ必要であり、信頼性のある操作ではありません。
  • キューアイテムのプルのペースはコンシューマが制御できるため、キュー内の負荷ピークを一時的にバッファできます。
1
Joeri Sebrechts