HTTP REST APIを提供するソフトウェアシステムを開発しています。非常にモジュール化された柔軟な設計を実現したいので、コア機能と機能モジュールがあり、各特定の機能に関連するロジックです。目標は、各モジュールをコアや他のモジュールに手動で接続する必要なしに、柔軟な方法でモジュールを追加/削除できるようにすることです。コアは非常に小さく、機能に依存しないようにする必要があります。
イベントベースのアーキテクチャが私の目標の良い候補であることを発見しました。
ただし、堅牢な方法で実装することにはいくつかの困難があります。
1。情報共有への取り組み方
最初に、アプリケーション内で(たとえば、ユーザー要求の処理中に)ロジックが実行されると、その周りにコンテキストがあります。たとえば、一部のエンティティがデータベースから読み込まれました(このためにORMライブラリを使用しています)。そして、イベントを発生させたいです。
イベントでどのデータを渡す必要がありますか?私は2つのアプローチを見ることができます:
最初のアプローチでは、データはイベントからすぐに使用でき、これは便利です。ただし、以前のイベントでデータに変更が加えられた場合はどうなりますか?イベントハンドラーが分離されているため、確実にはわかりません。したがって、渡されたデータはすでに古くなっている可能性があります。
2番目のアプローチでは、実際のデータではなくIDのみを送信するため、データベースから新しいデータを強制的にロードします。そのため、各イベントハンドラーは手動でエンティティをフェッチする必要があります。これにより、データの鮮度の問題は解決しますが、パフォーマンスの面で別の問題が発生します。単一のユーザー要求に反応する数十のイベントハンドラーがあり、それぞれがデータベースに要求を発行します。これは、データベースにストレスをかける非常に効果のないアプローチのように見えます。
2。並行処理(トランザクションの分離)を処理する方法
別の問題は、並行性の観点からコードが安全であることを確認する必要があることです。並列リクエストや、同じプロセスの異なる部分で同じデータを変更したくありません。これを行うには、データベーストランザクションとさまざまなロック機能を使用する必要があります。
また、トランザクションを開始してイベントに渡すことができるため、イベントハンドラーは同じ分離層を使用できます。または、各イベントハンドラーには独自のトランザクションがあります。しかし、これは再びデータベースのパフォーマンスの問題につながります。
ユーザーリクエストごとに新しいトランザクションを作成し、それを各メソッドに渡すことを考えていました。これには、データベースアクセス(直接またはイベントを使用)が必要です。したがって、すべての可能なイベントハンドラーを含む各リクエストは、単一のトランザクションで実行されます。これは良いアプローチですか?
一般的に、このアーキテクチャは多くの質問を引き起こします。このテーマに関する優れた本や記事にはとても感謝しています。それとも、柔軟性とモジュール性の点で私の目標を達成するためのより良いアプローチがありますか?
並行性(トランザクションの分離)を処理する方法
モジュール式の分離システムが必要な場合は、機能をモジュール/サービスに分割することが最善の方法です同期通信を必要としない彼らの機能を果たすために。
はい、これはすべてのCRUDベースのマイクロサービス、つまり基本的にHTTP APIを備えた単なるテーブルであると見なします。
つまり、すべてのイベントは、Fire-and-Forgetタイプのイベントでなければなりません。したがって、トランザクション境界がサービス境界を超えることはありません。そのため、通常は分散トランザクションは必要ありません。
情報共有への取り組み方は?
RESTful HTTPを実行している場合は、メッセージで主キーを渡さないでください。リソースが利用可能なURIを渡します。
ただし、繰り返しになりますが、受信側のピアにクエリを返すように要求するものや、何か他のものに渡すことはできません。受信者が各メッセージを完全に処理できるように機能を分割します。
次に、このスタイルの説明をいくつか示します: Self-Contained Systems 。
イベントでどのデータを渡す必要がありますか?
間違いなくidのみです。イベントは、何かが発生したことを通知するものであり、データコンテナを意図したものではありません。このアプローチでは疎結合が発生するため、データベースが負荷に対応していないことがわかった場合でも、その機能を独自のデータベースを持つ別のマシンに移動するのにそれほどの労力はかかりません。
しかし、データの再利用についてのあなたの発言は少し疑わしいと思います。ほとんどの場合、イベントはまったく異なるアクティビティを分離します。これは、ビジネスの観点から何かが発生したことを示しています。これは、一貫した(サブ)機能またはビジネスプロセスのステップが機能し、別のステップに従っていることを意味します。より一般的には、これは saga の概念を表しています。これは、各ステップが他のステップとは分離して実行されることを意味します。おそらく、各ステップは、独自のデータベースを備えた独自のマシンに常駐しています。
イベントのもう1つの有効なケースは、ドメインイベントのdddコンセプトです。通常、1つのユースケースがいくつかのサブステップで分割され、各サブステップは独自のアプリケーションサービスに実装されますが、各ステップは1つのデータベーストランザクションの一部です。 ここに例があります そのテクニックの。
- 並行性(トランザクションの分離)を処理する方法
特筆すべき点が2つあると思います。 1つ目は 結果整合性 の概念です。基本的には、すでに説明したことについてです。サブステップでユースケースを分割し、それぞれをACIDに従って扱います。巨大なトランザクションが発生しないようにするため、密結合とデッドロックを回避する方法です。
2つ目は、サービスの境界を特定することです。モジュールとは、(マイクロ)サービスです。したがって、主な目標は、サービスの境界を特定して自律的になるようにすることです。
一連の投稿 これらの問題をカバーすることは、あなたにとっていくらか興味があるかもしれません。