イベント駆動アーキテクチャとは? 起きた出来事に反応する仕組み
イベント駆動アーキテクチャ (EDA) は、コンポーネント同士が直接呼び出し合うのではなく、イベントを発行し反応することで接続します。
イベント駆動システムでは、あるサービスが何かが起きたこと (注文が入った、ファイルがアップロードされた) を通知し、他のサービスが関心があれば反応します。プロデューサーはコンシューマーを知らず、待つこともありません。この疎結合は強力ですが、多くの複雑さをリクエストの流れから、CIでテストしにくい非同期の振る舞いへと移してしまいます。
呼び出しではなくイベント
サービスAがサービスBを呼び出して待つのではなく、Aはイベントをブローカーに発行してそのまま進みます。任意の数のコンシューマーがサブスクライブできます。プロデューサーとコンシューマーは、時間の面でも互いを知るという面でも疎結合になります。
チームがこれを選ぶ理由
- 疎結合: プロデューサーはコンシューマーに依存しません。
- 容易な拡張性: プロデューサーに触れずに新しいコンシューマーを追加できます。
- 自然なバッファリング: スパイクはキューに吸収されます。
- レジリエンス: 遅いコンシューマーがプロデューサーをブロックしません。
難しい部分
非同期の流れは追跡や推論がより難しくなります。単一のコールスタックは存在せず、振る舞いはサービス群にまたがって創発します。順序付け、重複配信、結果整合性はいずれも、設計で対処しなければならない現実の問題になります。
CIでイベントフローをテストする
ユニットテストはハンドラーを単独でカバーしますが、エンドツーエンドのイベントフローを検証するには通常、実際の、あるいはシミュレートされたブローカーが必要です。CIではブローカーをservice containerとして起動し、テストイベントを発行して結果の状態をアサートすることが多く、これは同期APIテストよりも遅くなります。
プロデューサーとコンシューマーのデプロイ
イベントは契約であるため、イベントスキーマの変更は独立してデプロイされたコンシューマーを壊すおそれがあります。バージョン管理されたイベントと後方互換のあるスキーマにより、一斉デプロイを調整することなくプロデューサーとコンシューマーを別々にロールアウトできます。
ブローカーを使った統合テスト
実行ごとにブローカーを起動する統合テストは、単純なユニットテストよりも重くなります。ウォームなマネージドrunner (Latchkeyなど) はその余分な起動コストを吸収し、イベントフローのテストでも素早く結果が返るようにします。
重要なポイント
- イベント駆動アーキテクチャは、発行・消費されるイベントを介してコンポーネントを疎結合にします。
- 同期的な単純さを、非同期の柔軟性とレジリエンスと引き換えにします。
- イベントスキーマは契約であり、バージョン管理することで独立したデプロイを安全に保てます。