SAP-C02-177 · セクション 20 / タスク 4.4
Publish / SubscribeとEvent-driven Architecture
Amazon SNS / Amazon EventBridge / Publish / Subscribe / Event Bus / Event Routing / Fan-out
既存アプリケーションでは、ある処理が完了した後に複数の後続処理を呼び出していることがあります。
例えば注文サービスが、
注文確定
↓
├─ 通知サービスを呼び出す
├─ ポイントサービスを呼び出す
└─ 分析サービスを呼び出す
という構成になっているとします。
この構成では、注文サービス自身が、
誰へ伝えるか
どの処理を起動するか
まで知っています。
そのため、
新しい処理を追加
↓
注文サービスを変更
↓
注文サービスを再デプロイ
という変更連鎖が発生します。
イベント駆動型アーキテクチャでは、こうしたイベントの発生元と、そのイベントへ反応する処理の責任を分離できるかを考えます。
1. 受信先を知りすぎている発行元を探す
モダナイゼーション候補として最初に確認するのは、
イベント発行元が
何個の受信先を直接知っているか
です。
例えば、
注文サービス
├─ 通知API
├─ ポイントAPI
├─ 分析API
└─ 不正検知API
のように、発行元がすべての受信先を直接呼び出しているとします。
この場合、
受信側を追加
受信側を削除
受信側のURLを変更
するたびに、注文サービス側の変更が必要になる可能性があります。
これは、注文を確定する責任と、注文確定後に誰が何をするか決める責任が同じアプリケーションへ集まっている状態です。
疎結合化では、この2つを分離できるかを確認します。
2. Event-driven Architectureでは「起きた事実」を発行する
イベント駆動型アーキテクチャでは、イベントはシステム内で何かが起きたことを表します。
例えば、
注文が確定した
という事実です。
一方、
メールを送信する
ポイントを付与する
分析処理を開始する
は、それぞれ特定の受信側に実行してほしい処理です。
発行元がこのような処理指示をすべて生成すると、
発行元
↓
受信側の存在や責任を知る
という結合が残ります。
代わりに、
注文サービス
↓
「注文が確定した」
という業務イベントを発行
し、
通知側
→ 通知が必要なら反応
ポイント側
→ ポイント付与が必要なら反応
分析側
→ 分析が必要なら反応
という形を検討します。
重要なのは、
発行元
=
何が起きたかを知らせる
受信側
=
その出来事に対して
自分が何をするか決める
という責任分離です。
3. Publish / Subscribeの機会は発行元が持つ購読先管理から探す
Publish / Subscribeの仕組み自体ではなく、既存発行元が受信側一覧を管理しているかを確認します。
例えば注文サービス内に、
通知サービス
ポイントサービス
分析サービス
という送信先一覧が保持され、新しい処理を追加するたびに一覧や送信処理を変更しているとします。
この場合、イベントを発行する責任と、誰がそのイベントを受け取るかを管理する責任が発行元へ集まっています。
モダナイゼーションでは、
発行元
↓
業務イベントを発行
購読関係
↓
発行元とは別に管理
できるかを評価します。
Publish / Subscribeを採用する価値は、受信側の追加・削除を発行元アプリケーションの変更から分離できるかという観点で判断します。
4. Fan-outの機会は受信側追加の変更履歴から見つける
Fan-outを検討する際は、
同じ出来事を利用する処理が
時間とともに増えているか
を確認します。
例えば当初は、
注文確定
↓
通知
だけだったものが、
通知
ポイント
分析
不正検知
監査
と増え、そのたびに注文サービスへ新しい呼び出し処理を追加しているとします。
この変更履歴から、
受信側の増加
↓
発行元の変更量も増加
していることが分かります。
このような場合、
1つの業務イベント
↓
複数の独立した利用側
というFan-outの境界へ移すことで、受信側の数と発行元の変更量を分離できるかを評価します。
5. Amazon SNSは独自の複数配信責任を外せるかで評価する
既存アプリケーションでは、発行元が独自に、
送信先一覧を保持
各送信先へ順番に送信
送信先追加時にコード変更
している場合があります。
例えば、
注文サービス
↓
独自の複数配信処理
↓
通知 / ポイント / 分析
という構成です。
すでに学習したAmazon SNSのPublish / SubscribeとFan-outを前提として、ここでは、
注文サービスが持っている
複数配信の責任
↓
Amazon SNSへ移せるか
を評価します。
目標は、
注文サービス
↓
注文イベントを発行
購読側の追加・削除
↓
注文サービスとは別に管理
という責任分離です。
Amazon SNSの個別機能を改めて選択するのではなく、既存発行元から受信側一覧の管理責任を外せる箇所を特定することが判断対象です。
6. Event Busでは発行元からルーティング責任を分離する
別の密結合として、
発行元が
イベントの内容を確認して
処理先を決める
構成があります。
例えば、
注文サービス
if 国内注文:
会計処理A
if 海外注文:
会計処理B
if 金額 >= 一定額:
監査処理
if 商品種別 == X:
専用処理
のように、イベントの内容と処理先の関係を発行元コードが持っている状態です。
この構成では、
ルーティング条件を変更
↓
発行元コードを変更
↓
発行元を再デプロイ
する必要があります。
ここで、イベントを発行する責任と、イベントをどこへ届けるか決める責任を分離できるかを考えます。
7. Event Busの機会は独自イベント中継処理から探す
既存システムによっては、複数アプリケーションからイベントを受け取る独自のイベント中継サービスが存在します。
例えば、
販売システム ─┐
在庫システム ─┼→ 独自イベント中継サービス
会員システム ─┘
となっており、この中継サービスが、
イベントを受信
イベント種別を判定
ルーティング表を参照
処理先へ転送
しているとします。
さらに、
新しいイベント送信元を追加
新しい受信先を追加
ルーティング条件を変更
するたびに、この中継サービス自体の設定やコードを保守している場合があります。
このような構成では、独自イベント中継サービスが持つイベント受信・配送の責任を確認し、Amazon EventBridgeのEvent Busへ移せるかを評価します。
ここで改めてEvent Busの基本機能を学ぶのではなく、自前でEvent Bus相当の責任を実装・運用している箇所を発見することが重要です。
8. Event Routingの機会はルーティングルールの変更頻度から探す
Event Routingのモダナイゼーション候補は、
イベント条件と処理先の関係が
どこで管理されているか
から探します。
例えば独自イベント中継サービス内に、
高額注文
→ 監査処理
海外注文
→ 海外会計処理
特定商品
→ 専用処理
というルーティング表があり、条件変更のたびに中継サービスを改修・再デプロイしているとします。
この場合の問題は、イベントの配送基盤と、業務イベントのルーティング条件の変更ライフサイクルが結合していることです。
すでに学習したAmazon EventBridgeのルールとイベントパターンを前提に、
独自中継サービスに埋め込まれた
Event Routing
↓
管理されたルールへ移せるか
を評価します。
これにより、ルーティング条件の変更を、イベント発行元や独自イベント中継コードの変更から分離できるかを確認します。
9. Amazon SNSとAmazon EventBridgeでは「何を発行元から外したいか」を見る
Amazon SNSとAmazon EventBridgeを単なる非同期サービスA、非同期サービスBとして比較しません。
Amazon SNSを評価しやすい兆候:
発行元が
複数の受信先を直接呼び出している
新しい受信側を追加するたび
発行元を変更している
この場合は、Publish / SubscribeとFan-outによって、受信側一覧を発行元から分離できるかを確認します。
Amazon EventBridgeを評価しやすい兆候:
発行元や独自中継処理が
イベントと処理先の対応関係を管理している
ルーティング条件変更のたび
アプリケーションコードを変更している
この場合は、Event BusとEvent Routingに相当する責任をマネージドな仕組みへ移せるか確認します。
判断の中心は、SNSかEventBridgeかという名前の比較ではなく、既存システムが本来持たなくてもよい責任をどこまで抱えているかです。
10. Event-driven Architectureでも発行元と受信側の契約は必要
イベント駆動型にしても、発行元と受信側の関係が完全になくなるわけではありません。
例えば受信側が、
注文ID
注文金額
顧客ID
注文状態
を必要とするなら、発行されるイベントには必要な情報が含まれている必要があります。
ただし、
通知サービスの内部テーブル名
分析サービスの保存方法
ポイントサービスのAPI URL
のような受信側内部の実装詳細まで、発行元が知る必要はありません。
目標は、「何が起きたか」を表すイベントを境界にして、発行元の業務責任と受信側の内部実装を分離することです。
11. Publish / SubscribeとWorkflowを混同しない
Publish / SubscribeやEvent Routingは、
出来事が発生した
↓
独立した処理が反応する
構成に適しています。
一方、
ステップ1
↓
ステップ2
↓
承認待ち
↓
条件分岐
↓
ステップ3
のように、現在どの処理段階か、どの順序で進むか、どの条件で分岐するかを一連の業務処理として管理する場合は、別の設計課題です。
したがって、イベント駆動化したからすべての処理をFan-outする、とは判断しません。
12. モダナイゼーション判断表
| 現在の状態 | 検討する変更 |
|---|---|
| 発行元が複数受信先を直接呼び出す | Publish / Subscribeを評価 |
| 新しい受信側を追加するたび発行元を変更 | Fan-outで受信側追加を分離 |
| 発行元が受信側固有の処理指示を生成 | 業務上起きた事実をイベントとして表現 |
| 独自に複数配信処理を実装 | Amazon SNSへ配信責任を移せるか評価 |
| 独自イベント中継サービスを運用 | Event Bus相当の責任をAmazon EventBridgeへ移せるか評価 |
| 独自中継コードにルーティング条件がある | Event Routingをルールへ分離できるか評価 |
| 順序・分岐・現在状態の管理が中心 | Fan-outとは別の設計課題として扱う |
13. 判断フロー
既存のイベント発行元を確認
↓
発行元が
受信先一覧を所有しているか
↓
はい
↓
同じ出来事を
複数の独立処理が利用するか
↓
はい
↓
Publish / Subscribe
+
Fan-outへ
責任を移せるか評価
↓
独自の複数配信処理を
Amazon SNSへ移せるか確認
別の経路では、
独自イベント中継処理があるか
↓
イベント受信・配送・
ルーティングを自前管理しているか
↓
はい
↓
Event Bus相当の責任を
Amazon EventBridgeへ移せるか
↓
ルーティング条件を
独自コードからルールへ
分離できるか
最終的に確認するのは、新しい受信側の追加、ルーティング条件の変更、受信側内部実装の変更が、イベント発行元または独自イベント中継アプリケーションの不要な変更へ波及しなくなったかです。