re:Invent 2024: AWSサーバーレスチームが語るPlatform Builder向けアプリケーション統合
はじめに
海外の様々な講演を日本語記事に書き起こすことで、隠れた良質な情報をもっと身近なものに。そんなコンセプトで進める本企画で今回取り上げるプレゼンテーションはこちら!
📖 AWS re:Invent 2024 - Application integration for platform builders (API311)
この動画では、Platform BuilderのためのApplication統合について、AWSのServerlessチームのPrincipal Solutions ArchitectであるSteveが解説しています。Event-drivenアーキテクチャにおける集中型と分散型のアプローチの融合方法や、EventBridgeを活用したEvent Busトポロジーの実装について詳しく説明されています。特に、Schema RegistryやDead Letter Queueを活用したフォールトトレランス、AWS Powertoolsによる運用効率化など、具体的な実装方法にも言及しています。また、Platform Engineeringチームが担うべき役割として、Event Catalogを活用したドキュメント作成やSubscriptionルールの一元管理による開発チームの負担軽減についても触れられており、実践的なPlatform構築のノウハウが詰まった内容となっています。
※ 画像をクリックすると、動画中の該当シーンに遷移します。
re:Invent 2024関連の書き起こし記事については、こちらのSpreadsheet に情報をまとめています。合わせてご確認ください!
本編
Platform Builderのためのアプリケーション統合:概要と目的
みなさん、こんにちは。私はSteveと申します。オーストラリアとニュージーランドのServerlessチームのPrincipal Solutions Architectを務めています。この地域でServerlessビジネスの運営を支援しており、本日はこちらに参加できることを大変嬉しく思います。今日は、Platform Builderのためのアプリケーション統合についてお話しさせていただきます。これは300レベルのセッションです。個々のサービスやその機能について深く掘り下げることはせず、皆さんがすでにある程度の知識をお持ちであることを前提にお話を進めていきます。
会場には、Platformチームに所属されている方や、Platformチームと協働されている方が多くいらっしゃると思います。Platformの開発チームの共通の目標は、基本的にビジネスを加速し、エンタープライズレベルのシステム運用に伴う全体的な複雑さを管理することだとご理解いただいていることでしょう。通常、このような場合、開発するPlatformに対してプロダクトマインドセットで取り組むことになります。 これには、インフラストラクチャ、コンテナオーケストレーション、継続的デプロイメント、モニタリング、セキュリティ、アプリケーションパフォーマンス管理などが含まれます。
Event-drivenアーキテクチャの重要性とEventBridgeの役割
しかし、アプリケーション統合についてはどうすればよいのでしょうか?アプリケーション統合は、ビジネス要件の重要な部分を占めています。 個々のビジネスコンポーネントを接続し、これらの異なるシステムやコンポーネントがシームレスに連携するようにすることで、効率性、データの正確性、スケーラビリティ、コスト削減を向上させることができます。 ここで一般的に取られているアプローチは、アプリケーション統合を支援するインフラストラクチャを中央で管理し、サービスとして提供する集中型アプローチか、あるいはアプリケーションチームがそのインフラストラクチャを管理する、より分散型のアプローチのいずれかです。
Serverlessで私たちが試みていることの1つは、これら2つの世界を融合させる方法を見出すことです。一方では共通インフラストラクチャの標準化と機能構築を目指し、もう一方では必要な製品や機能を構築するためのより大きな自律性を求めています。 統合の観点から見ると、私たちの主な目標は邪魔にならないことです。アプリケーション統合チームやPlatformチームが接続性の実現におけるボトルネックとなることは避けたいと考えています。チームがより自律的に運営できるようにエンパワーし、可能な限りポイントツーポイントの統合を排除したいと考えています。このような統合は環境にカップリングを導入し、変更や加速を困難にします。しかし同時に、Platformチームが目指す目標を達成するために、十分な監査とガバナンスを確保する必要もあります。
本日は、統合のアーキテクチャ原則とパターンについて見ていきます。Event-basedトポロジーが、集中化と自律性の概念をどのように結びつけるかについて重要な役割を果たすことを見ていきます。数年前に、Event Busトポロジーとそれがアーキテクチャに与える影響について話しましたが、これは統合をよりシームレスに機能させるための重要な要素です。また、Eventの設計スキーマとバージョニングについても話します。これらは、アプリケーション内でまとまりのあるEvent-drivenアーキテクチャを実現し、Platform Engineeringが環境の加速と安定性の実装をどのように支援できるかという点で、非常に重要な要素です。もちろん運用上の懸念もあります。システムの信頼性を確保し、メッセージの損失が頻繁に発生しないようにする必要があります。損失が発生した場合は、それらの障害から回復する方法が必要です。機密データの取り扱いや、その対処方法、そして可観測性についても考慮する必要があります。これらすべてが、最終的にEvent-drivenアーキテクチャのためのControl Planeを構築するという考えにつながっていきます。このEvent-drivenアーキテクチャのControl PlaneはAmazon EventBridgeによってサポートされることになります。
AWSインテグレーションサービスとEvent Busトポロジーの解説
アーキテクチャの原則という観点から、これらのサービスがどこに位置するのかについて考えてみましょう。 私たちには、さまざまな種類の統合を実現するための多くのインテグレーションサービスがあります。EventBridgeは主に、境界づけられたコンテキスト(Bounded Context)間でのサービス間通信と統合を支援します。これはDomain-Driven Designの用語を借用していますが、EventBridge Pipesは別の機能で、システムを流れるメッセージの変換や変形を行う際に使用される、より点と点を結ぶ統合向けのソリューションです。
SQSとStep Functionsは、非同期の点と点の統合を実現し、さらにワークフローやデータ処理のオーケストレーションも支援します。これらのサービスは、基本的にさまざまな種類の統合パターンをサポートしています。これらが重要な理由は、アーキテクトやプラットフォーム開発者として、パターンとそれらがアプリケーション統合や構築するサービス、アプリケーションに与える影響について考える必要があるからです。 これから、サービス間、つまり境界づけられたコンテキスト間で何が起こるのか、そしてEventBridgeを使用してイベントやメッセージがシステム内をどのように流れるのかに焦点を当てていきます。
EventBridgeを中央集権的なイベント配信の形態として考える際、多くの人が最初に採用するのは、アプリケーションが送信するすべてのイベントが流れる中央イベントバスを持つこのモデルです。しかし、クロスアカウントでイベントを配信するためには、実際にはメッセージを受信するアカウントにイベントバスが必要であることにすぐに気付きます。 これには後で説明するメリットがありますが、基本的に受信アカウントは中央イベントバスに必要な権限を付与する必要があります。これは自動的には行われません。イベントの流れが安全に行われることを確実にするために、さまざまな保護手段や保証を設定することができます。
ここでのポイントは、セキュリティが実装されると、中央で管理された配信チャネルを通じてすべてのイベントを管理することになり、これは基本的にネットワークが不要であることを意味します。これはすべてAWSプラットフォームの機能の一部です。アプリケーションの構成と配布について考える際、多くのお客様が採用している一般的なアプローチは、特定のドメインがそのバスに存在するマルチアカウント戦略です。これにはセキュリティやコストの考慮事項など、さまざまな理由があります。
単一のアカウントに複数のドメインがある場合、ドメインという考え方が、これらのリソースをアーキテクトし管理する方法において中心的かつ重要な役割を果たします。 ここでの考え方は、ドメインを識別し、それらをサービスの境界を越えて共有し、ドメイン内のすべてのものが自由に利用できるようにするメカニズムを持つことです。これにより、これらのドメイン名やネームスペースを認識し、識別し、リソース管理の手段として使用する方法に一貫性を持たせることができます。これらは、サービスやリソースの命名だけでなく、フィルタリングルールやアプリケーションの実装など、さまざまな場所で使用されます。一貫したアプローチを持つことは、環境の一貫性を確保する上で重要です。Parameter StoreやAmazon Resource Access Managerなどを、アカウント間で情報を共有する方法として検討できます。Amazon Resource Access Managerは、情報をアカウント間で共有し、企業全体でアクセス可能にする方法として使用します。
Event Busポリシーとクロスアカウント配信の実装
ここから、考慮すべき事項についてのチェックリストを作成していきます。 パブリッシャー側では、Platform teamが集中管理するEvent busがあり、すべてのパブリッシャーがそのEvent busにイベントを送信しています。環境全体で共有している、中央で定義されたドメインもあります。サブスクライバー側では、イベントを受信するためのEvent busが必要で、そのEvent busがドメインと整合していることを確認します。
典型的なイベントフローは次のようになります。 この例では、Salesドメインが中央のEvent busにイベントをパブリッシュします。中央のEvent busは、そのドメインやサービスがイベントをパブリッシュできるようにするポリシーを定義する必要があり、これはResource policyを通じて実現できます。これについては後ほど説明します。イベントがEvent busに到着すると、受信者のアカウントにメッセージを送信するためのRuleが必要になります。基本的に、ターゲットは相手側のEvent busだけです。Billingドメインでは、EventBridgeがBillingドメインのEvent busにイベントを送信するために必要な権限を持っているというポリシーを定義する必要があります。Billingアカウントでイベントを受信すると、アプリケーションチームはそのEvent bus上でRuleを作成し、必要に応じてイベントを処理できます。
ここで問題となるのは、誰がRuleを所有するのかということです。 イベント駆動アーキテクチャとパブリッシュ/サブスクライブパターンの核となる原則は、パブリッシャーとサブスクライバーを分離できるという考え方です。これは、サブスクライバーが自分の必要とするRuleや、サブスクライブしたいものを定義し、そのイベントをどのように処理したいかを制御するということを意味します。つまり、中央のEvent bus上のRuleとBilling Event bus上のRuleの両方を所有する必要があるということです。もしこの関係が逆になると、中央のEvent busの所有者がすべてのイベントの送信先を知っている必要が出てきてしまいます。これでは、単一の当事者がすべての配信先を知る必要が出てきてしまい、パブリッシュ/サブスクライブの目的が損なわれてしまいます。
ここでは2種類のRuleがあります。 1つ目は、ここで仮にSubscription Ruleと名付けたもので、どのイベントをサブスクライブするか、そのイベントをどこに送信するかを定義します。2つ目のIntegration Ruleは、アプリケーションチームが定義するもので、そのイベントをどのように処理するかを決定します。Lambda関数やSQS Queue、あるいはState Machineで処理することもできます。EventBridgeには20以上のネイティブ統合があり、イベントを直接処理することができます。
では、BillingアカウントがRuleを所有している場合、Billingが所有していない中央のEvent bus上でどのようにRuleを作成するのでしょうか?これを実現するのがResource Policyです。 Resource Policyを使用すると、他のエンティティやプリンシパルに対して、所有していないリソース上にリソースを作成する権限を与えるポリシーを作成できます。このコールチェーンを実現するために最初に必要なのは、SalesアカウントがEvent busにパブリッシュすることを許可するEvent Bus Policyを作成することです。これは重要なセキュリティ機能で、中央のEvent busに登録されていない未承認のドメインからのパブリッシャーがイベントを送信できないようにします。
そのEvent Busポリシーは、このようなものになります。ここではPut Eventのパーミッションを付与します。イベントがSalesドメインから送信される限り、イベントアクションを許可します。次に必要なポリシーは、BillingがEvent Bus上でルールを作成・管理できるようにするものです。このポリシーは次のようになります。このアカウントのプリンシパルはBillingアカウントで、特定の条件を満たす限り、ルールの作成と管理が可能です。イベントソースが一致する必要があり、空のフィルターを持つルールは作成できません。これにより、Billingサービスは自身のリソーススタック内でルールを定義でき、そのルールは中央のEvent Busに配置されます。
パズルの3つ目のピースは、EventBridgeが受信アカウントのEvent Busにイベントを送信できるようにする必要があります。このポリシーは1回だけ定義すれば良いので便利ですが、これによりEventBridgeはクロスアカウントでのイベント配信が可能になります。最後に、サブスクリプションルールがあります。これはアプリケーションチームによって定義され、そのイベントがどのように処理されるかを実質的に決定します。
これで、パブリッシャー側では、サブスクライバー側とパブリッシャー側の両方でポリシーを作成する機能を追加し、この統合を実現できるようになりました。リソース構成の観点からは、スタックに必要なリソースをいくつか定義し始めることができ、これを段階的に構築していくことになります。
マルチバストポロジーとイベント設計の考え方
これが単一バストポロジーのアプローチでした。では、マルチバストポロジーのアプローチはどうでしょうか?どのように異なるのでしょうか?今まで見てきたのは、すべてのイベントが単一のEvent Busを通過する方式でした。マルチバストポロジーは次のようになります:すべてのイベントが流れる中央バスは存在しません。サブスクライバーが持つ関係性は、イベントのパブリッシャーと直接結ばれることになります。これらの制御はよりアプリケーションチームの手に委ねられ、アプリケーション統合においてより分散化されたアプローチを表しています。
さて、これは先ほど見ていた内容ですが、根本的な違いは、実際には特別な対応は必要ないということです。ただし、これらのポリシーを定義する責任が、それぞれのドメインに移ることになります。では、なぜマルチバストポロジーを使用するのでしょうか?これにより、アプリケーションチームがより多くの制御権を持ち、中央サービスへの依存関係が減少します。これが強化する重要な点の1つは、パブリッシャーが環境の他の部分との関係性を把握できることです。すべてのサブスクリプションが独自のEvent Busに配置されるため、誰が自分たちのイベントをサブスクライブしているかを確認でき、公開しているイベントの管理と進化がより容易になります。
では、両方の利点を得るにはどうすればよいのでしょうか?私は、これを単なるリソース使用率の問題としてだけでなく、次のように考え始めています。ご覧のように、現在のEvent Busには、中央のEvent Busに配置できるイベント数を制限する制約があります。非常に大きなドメインがある場合、これらの制限にすぐに到達してしまう可能性があります。しかし、ドメインを整理するための集中的なアプローチを取りながら、ルールの作成場所やイベントの発行方法を分散させることについてはどうでしょうか?これは、コンシューマーとの直接的な関係を持つマルチバストポロジーで構築しようとしているのと同じコンセプトですが、プラットフォームアカウントでEvent Busを論理的に複製しているだけです。これにより、ルールの配置場所を分散させながら、特定のドメインから発行されるイベントとそれを購読するサブスクライバーとの整合性を取ることができます。
このアプローチを取れば、それほど多くの追加作業は必要ありません。必要なのは、環境内の各ドメインに対してドメインEvent Busを作成し始めることだけです。すべてのフローが通過する1つの中央集中型の場所という考えを、ドメイン固有のEvent Busに置き換えているのです。
イベント設計について話しましょう。これまでのイベントに参加された方なら、このイベントの定義を何度も目にしたことがあるでしょう。イベントは基本的に、システムの状態が変化したことを示すシグナルです。しかし、イベントの核となる原則には、それが不変のオブジェクトであるという事実も含まれています。これは、イベント設計において非常に重要でありながら、しばしば見過ごされる部分です。なぜなら、私たちが本当に理解しようとしているのは、過去に起こったことは変更できない - それは歴史だということです。何らかの目的で特定のイベントを修正する必要があると感じた場合、そのイベントのモデル化方法を見直し、そもそもそれがイベントと呼べるものなのかを考え直す必要があるかもしれません。
さらに重要なのは、これがシステム間の契約だということです。この契約は、ビジネス内のエンティティとの関係を構築する際に確立されます。これらの関係には理由があり、これらのイベントによって強化されています。これまでの経験で見てきたアンチパターンには、イベントをデータ転送オブジェクトとして偽装することが含まれます。これはイベントの本来の意図ではありません。イベントにどれだけの情報を含めるべきかという質問がよく出てきますが、コツは、それらのイベントのコンシューマーが他のシステムから自律的に動作するために必要な最小限のコンテキストを理解することです。
また、イベントを他のシステムに何かを指示する手段として使用するアンチパターンもあります。これもまた、イベントの本来の意図ではありません。サイズや複雑さでイベントを分類し、用語を使用することは、ここでの意図ではありません。私たちが欲しいのはビジネスコンテキストであり、イベントをFatやSkinny、SmartやDumbといった言葉で表現したくはありません。これらは、イベントの種類や、この統合手段を通じて確立したい関係の種類について何も教えてくれません。前述のように、イベントを変更することもアンチパターンです。不変性という考えを守りたいのです。
イベントタイプとバージョニング:効果的な実装戦略
イベントにどの程度の情報を含めるべきかについての最新の考え方として、イベントにポインターを含めるというアプローチが議論されています。これは、イベントのサイズや転送の制約が制限要因となる場合に検討される方法です。しかし、このアプローチはネットワーク上の特定の場所との結合度を高めてしまうため、難しい面があります。また、データを管理するチームは、セキュリティアクセスなどの考慮事項と共に、Observableの特性を確実に維持する必要があり、このアプローチの実装を複雑にしています。
さまざまなタイプのイベントについて見ていきましょう。 Martin Fowlerによる定義が分かりやすいと思います。彼は一部のイベントを通知イベント(Notification Events)として分類しています。これらは非常にシンプルで、多くの情報を含まないイベントで、通常、イベントを消費する他のシステムが追加情報を問い合わせる必要があります。また、Event-Carried State Transferイベントという概念もあります。これは、データの変更をイベントとして公開する際に非常に有用です。ここでの課題の一つ、そしてEvent-Carried State Transferイベントを考える上での一つの方法として、DynamoDB Streamイベントタイプを例に挙げることができます。これはドメイン内でReactiveな処理を行いたい場合には優れたイベントです。ただし、これはサービス境界を越えて共有するべきものではありません。なぜなら、ビジネスイベントとしての文脈が欠けているからです。
さらに、このアプローチは実装の詳細を外部に露出してしまいます。このイベント構造を見れば、DBを使用していることが明らかで、これはサービスの自律性という考え方に反します。ただし、このアプローチは、ドメイン内で有用な場合があります。例えば、Amazon EventBridge Pipesを使用してイベントを変換し、サービス境界を越えて公開したいドメインイベントを表現することができます。
ドメインイベントは、Martin Fowlerが定義した最後のイベントタイプで、Vaughn Vernonなど他の専門家も定義しています。これは前述の2つのタイプを組み合わせたもので、できるだけドメインに近い形でモデル化されたイベントです。EventBridgeの観点からは、EventBridgeエンベロープを使用してドメインイベントを構造化できます。このイベントエンベロープには、文脈を定義するための重要なフィールドがあります。Event SourceとDetail Typeは、ドメイン内でイベントを一意に識別する複合キーとして機能し、Sourceはドメインを、Event Detail Typeはイベントの種類を表します。Detailには、そのイベントの一部としてモデル化された情報が含まれ、他者と共有したい必要なコンテキストがすべて含まれています。
長年にわたって議論されてきたパターンの1つに、メタデータの包含があります。これは基本的に、EventBridgeエンベロープの制約によって推進されてきました。システム内でイベントが流れる過程でIDフィールドが変化するため、エンベロープのIDフィールドだけではイベントの一意性を保証できないからです。イベント内にMetadataオブジェクトを含めることは、Detailそのものに十分な情報がない場合に、べき等性IDを定義してイベントを一意に識別する手段として多くの人が採用してきたアプローチです。また、このイベントではバージョンの変更も不可能なため、それを行うための別のメカニズムを考える必要があります。
では、バージョニングとスキーマについて説明していきましょう。 Adam BellemareのBuilding Event-Driven Microservicesという本から、とても良い引用があります。重要なポイントは、暗黙的なデータ契約は脆弱で制御されていない変更の影響を受けやすいということです。これは、スキーマがEvent-Drivenアーキテクチャにおいて重要な役割を果たすという考えを裏付けています。AWSの観点から見ると、EventBridgeは複数の異なるタイプのスキーマをサポートしています。 AWSには数百のAWSサービスがEventBridgeを通じてイベントを発行しているスキーマレジストリがあり、これらのイベントをITの自動化やDevOps、AWS環境の変更管理などの用途で利用することができます。
Discovered Schema Registryは、Event Busでスキーマディスカバリーを有効にすると利用可能になります。EventBridgeはそのEvent Busを流れるイベントを確認し、スキーマを自動生成してレジストリに登録します。これは開発段階で、自分でスキーマを管理したくない場合に便利な機能です。また、これらのイベント定義を独自のCustom Schema Registryにマージすることも可能です。本番環境レベルでは、そのようなアプローチを取る方が望ましいでしょう。特定のドメインが発行するすべてのイベントのスキーマをグループ化できるため、サブスクライバーはそのドメインがプラットフォームの観点からどのようなイベントを発行しているかを確認できます。
環境内のドメインに合わせてスキーマレジストリを配置し、中央からアクセス可能にすることは非常に理にかなっています。実際のスキーマやイベント定義は、イベント定義の文脈を確立するアプリケーションチームが所有すべきものです。これは通常、プラットフォームチームが担当する責務ではありません。しかし、 これらのレジストリを他のチームからもアクセス可能にし、アプリケーションチームがスキーマを進化させる際に必要なアクセス権を提供したいと考えています。
ここでバージョニングの話に移りましょう。私たちはすでにイベントをシステムの状態が変化したことを示す信号として定義しました。この定義で恐らく欠けているのは最後の部分、つまり「特定の時点で」という要素です。イベントに対する私たちの理解が変化した場合、イベントの構造もその時点でのイベントを表現するものでなければなりません。イベントは不変なものですから、新しい定義を作成する必要があります。
組織内でイベントのバージョニングを考える際、サブスクライバーが誰なのかを知ることは非常に重要です。なぜなら、通常イベントは単独でバージョン管理されるわけではないからです。イベントの変更とその伝達は協調的な方法で行う必要があります。ある日突然オフィスに来て、勝手にバージョン2に変更するようなことはできません。そんなことをすれば、誰もが困ることになるでしょう。 ここでの考え方は、ドメインイベントがどのようなものかを理解することです。これは実際、サブスクライバーがイベントに関するより多くのコンテキストや情報を要求する可能性のある環境の他の部分からの影響を受けるかもしれません。その後、他のサブスクライバーもその情報を活用できるかどうかについて議論することができます。ここでの重要なポイントは、これが協調的な空間であり、突然の変更ではなく、バージョンの移行と進化を制御された方法で行えるということです。
イベントを変更する際、バージョニングによって互換性に関する興味深い定義が生まれます。1つ目はForward互換性で、これはSubscriberに影響を与えることなく、新しいバージョンのスキーマでイベントを生成できる状態を指します。これは非常によく使われる方法です。既存のSubscriberの動作を妨げることなく、イベントにフィールドを追加できることが分かっているためです。 もう1つのアプローチはBackward互換性に関するもので、これは新しいバージョンのスキーマを実際に公開する前に、Subscriberが新しいバージョンのスキーマを使用できる状態を指します。
理想的には、この両方の利点を活かせることが望ましいです。 イベントとその進化において、ForwardとBackwardの両方の互換性を活用できるように設計したいところです。 EventBridgeについては、Atomic Versioningのみをサポートしているということを理解しておく必要があります。イベントスキーマを作成または変更すると、実際には全く新しいバージョンのスキーマが作成されます。私の意見では、これは実は悪いアプローチではありません。なぜなら、組織全体でどのように変更を移行していくかについて考えることを強制し、明示的なデータ契約の公開に依存するからです。顧客によく採用されているSemantic Versioningは、システム内でのForward互換性を重視したアプローチですが、古いバージョンのイベントのConsumerに追いつくことを強制するメカニズムは提供していません。これは、公開されているイベントに何らかの互換性があることを前提としているためです。
Event-drivenプラットフォームの運用上の懸念事項と対策
これは暗黙の契約という考え方に依存しており、時間とともに管理が難しくなる可能性があります。また、特定のイベントに対する私たちのビジネスの現在の考え方を実際に表現できていません。パブリッシャーの観点からすると、常に最新バージョンのイベントを公開したいと考えるためです。遅かれ早かれ、破壊的な変更を導入することになり、結局はAtomic Versioningによるアップグレードを強制されることになります。
これらは、Detail Typeの末尾にバージョン番号を追加したり、 メタデータ内にバージョン番号を含めたりするなど、顧客が採用している手法の一部です。しかし、これらはいずれも定義したスキーマとの明示的な関係を表現していません。代替アプローチとして、Schema Registryとの統合をより良くする方法を検討してみましょう。スキーマを定義して公開する努力をしているのですから、 そのスキーマ定義を特定のイベントと紐付けてはどうでしょうか。これはより明示的なアプローチです。なぜなら、イベントが特定のソースから来たことを実際に検証できるからです。
ここでPlatform Engineeringが役立ちます。 CyberArkのRan Isenbergは、Platform Engineeringが私たちのベストプラクティスを強化し、開発者の作業を加速させる方法について多くの議論を重ねてきました。プラットフォームの観点からは、 私たちの統合プラットフォームの周りに構築するものが、最新バージョンのスキーマを公開することやメタデータの定義方法を知る必要がないことなどを確実にするのに役立つようにしたいと考えています。また、サービスがダウンしたりEventBridgeのエンドポイントにアクセスできない場合でも、メッセージを失うことなく確実に復旧できる耐久性のあるバッファを持つシステムを確保したいと考えています。
Event-driven architectureにおいて重要なポイントの1つは、履歴に抜け漏れがあってはならないということです。そのため、パブリッシング側とスキーマ検証の両面から、どのように保護するかを考える必要があります。先ほど触れたように、最新のイベントを確実にパブリッシュできるようにしたいと考えており、そのためにSchema Registryを活用できます。私たちが作成して共有する可能性のあるユーティリティは、これらのスキーマをローカルにキャッシュすることができます。常にクラウドにアクセスしてその情報を取得する必要はありません。開発チームが既にスキーマを定義している場合、そのスキーマにアクセスできるはずです。
イベントを送信する前に検証を行うことは非常に理にかなっています。コンシューマー側から「何か間違っている」と指摘されたり、サーバーサイドの検証を通じて「適切なイベントがパブリッシュされていない」ことを発見したりするのを待つような設計は避けるべきです。そのような方法では、サブスクライバーとの契約を破ることになってしまいます。また、メタデータはインフラストラクチャレベルの考慮事項であるため、アプリケーション開発者がメタデータの扱い方を知る必要はありません。これは定義したライブラリが処理すべきことです。
メタデータはコンテキストの観点から見ると実際には非常に有用だと言えます。しかし、現在お客様に推奨している配置場所は、おそらく適切ではありません。なぜなら、イベントデータは、システムでモデル化しているドメインイベントを一意に表現すべきだからです。この例を見てみましょう。左側の例ではCustomerMadePreferredイベントをイベントの意図として定義しています。一方で、イベントオブジェクト内にメタデータをモデル化していますが、これは開発チームがメタデータの管理と設定方法を知る必要が出てくるため、あまり理にかなっていません。
では、この問題をどのように解決すればよいのでしょうか?以下に例を示します。詳細情報とメタデータの作成をカプセル化したイベントをパブリッシュするための手段を提供する、Eventingライブラリを作成します。
これらのライブラリを使用すると、PutEventを呼び出す際に、すべての機能がイベント内にカプセル化され、開発者はモデル化したいイベントをパブリッシュするだけで済みます。ここまでの進捗を確認しましょう。私たちは現在、中央で管理されているSchema Registryを持ち、すべてのイベントを共有しています。これは後ほど、Control Planeがリソースの観点からこの進化をどのように管理・促進できるかについて議論する際に重要になってきます。
Schema Registryと、Publishingドメインがパブリッシュするイベントの進化を管理するために必要なすべてのアクセスポリシーを追加するだけです。 では、Event-drivenプラットフォームを進化させる際に考慮すべき運用上の懸念事項について見ていきましょう。
特に金融サービスのユースケースでよく出てくる課題の1つが、ドメイン境界を越えて機密情報を共有することです。重要な問題は「イベントを通じてどの程度の機密データを共有すべきか」ということです。まず自問すべきなのは、そもそも機密データの共有が本当に必要なのかということです。ドメインは適切にモデル化されていますか?他のサービスはその機密情報にどのような依存関係があるのでしょうか?なぜそれらを自律的に管理できないのでしょうか?というのも、ドメイン境界を越えて機密情報を共有し始めると、そのデータの整合性を管理する責任が消費側のサービスに移り、運用上の管理がより困難になるからです。
情報共有の方法を検討する場合、何らかの暗号化について考える必要があります。これはEventBridgeレベルで、情報の消去またはデータの暗号化によって実現できます。 最近、AWS Encryption SDKを作成しました。これを使用することで、受信した情報を検査し、ライブラリのクライアントをインストールして初期化し、データを解読するために必要なキーを提供し、処理が必要な情報の暗号化または復号化を行うことができます。
ここでAWS Powertoolsをご紹介したいと思います。これはベストプラクティスの実装を簡素化するのに役立つツールキットです。Powertoolsには、Serverlessアプリケーションの運用面に対応する多くの異なるツールが用意されています。 その中にData Masking Utilityがあり、これについて見ていきましょう。 このユーティリティは、AWS Encryption SDKの実装をカプセル化し、その実装を1〜2行程度にまで簡素化します。また、Encryption SDKにはない情報の消去機能も備えています - Encryption SDKは暗号化のみを扱います。
暗号化メソッドはSDKの実装ですが、アプリケーション全体での呼び出し方を簡素化しました。 次はフォールトトレランスについて話しましょう。これは、Event-drivenアーキテクチャ全体でのエンドツーエンドの配信と、イベントの安全な配布を確実にする上で重要な部分です。 数年前、ターゲット設定用のDead Letter Queueの概念を導入しました。デフォルトでは、EventBridgeは配信に失敗した場合、最大24時間まで再試行を行います。しかし、24時間も待ちたくない場合や、メッセージをDead Letter Queueに送信する前に実行される再試行回数をコントロールしたい場合があるでしょう。そこでポリシーの出番となります。
Dead Letter Queue の設定が定義されると、その真価が発揮されます。エラーをキャプチャしたり、そのキューにメッセージが届いたりすると、システム内の潜在的なエラー を特定するのに非常に役立ちます。これは、誰かが意図せずにリソースを削除してしまった場合や、セキュリティエラーが発生した場合などに起こり得ます。このような状況のトラブルシューティングや、メッセージを元のソースに再送信する 機能として非常に有用です。
ここで問題となるのは、このリソースの所有者は誰か、そして誰が所有すべきかということです。Subscription Rule と Integration Rule をサブスクライバーが所有している場合、Dead Letter Queue の定義についても彼らが責任を持つべきでしょう。しかし、いくつ必要で、どこに配置すべきなのでしょうか? 私の提案としては、各ターゲットごとに Dead Letter Queue を設置するのではなく、特定のドメインに合わせて配置することをお勧めします。また、各統合ポイントに Dead Letter Queue を必ず設置してください。この場合、最初の統合ポイントは Subscription Rule です。Event Bus 間の配信に失敗した場合、それらのメッセージをすべて Central Event Bus に再送信し、 意図したターゲットに送信することができます。
同様に、アプリケーション側にもドメイン固有の Dead Letter Queue を設置することで、イベントを処理している特定の処理統合を検査し、メッセージを直接意図したサブスクライバーに対して再生または処理することができます。このように、Subscription Role と Integration Role の両方のサブスクライバー側に Dead Letter Queue を追加しました。 これにより、リソースの構成の観点からは、管理すべき追加リソースが増えることになります。
Observability の観点から見ると、 これはプラットフォームチームとして運用する上で重要な部分ですが、Event Bus の特性や Rule の動作状況を監視しています。新しい Rule Name Dimensions を導入し、Invocation Attempts、Successful Invocation Attempts、Retry Invocation Attempts などを監視できるようになりました。 これは特に、リトライがどこで発生しているかを把握し、キューに入ってくるエラーメッセージの深さを確認する際に非常に役立ちます。
また、エンドツーエンドの遅延監視という考え方も導入しました。 これにより、必ずしも Rule の処理方法に関連しない可能性のあるボトルネックやパフォーマンスの問題を特定することができます。これは特に、EventBridge との統合全体のパフォーマンスを理解する上で非常に有用です。Central Event Bus やプラットフォームチームに、そしてサブスクライバー側にも、アプリケーションとの統合がどのように失敗しているかを理解するために、ドメイン 固有のメトリクスを追加する予定です。
Platform Engineeringによるイベントストリーム管理の未来
そこにはかなりの要素が含まれており、これらのリソースの責任は各Subscriberに明確に割り当てられています。では、どうすれば邪魔にならないようにできるでしょうか?アプリケーションチームがこれらを管理する必要がないように、どうすれば物事をより簡単にできるでしょうか?まだ彼らがやるべきことがたくさんありますからね。サービス間やアカウント間のコミュニケーションの責任を、Platformチームに委譲してはどうでしょうか?そうすれば、すべてのドメインアカウント、ポリシー、そしてSubscriptionルールを管理する能力を持つことができます。これにより、イベントがSubscriberのアカウントに届く方法についてある程度のコントロールを持つことができます。
アカウントチームがアプリケーションチームとその情報を管理する必要がなくなったため、今では標準化された方法でそれを実現できます。アプリケーションチームは、イベントを処理するために必要な統合ルールの定義方法と、Queueの設定、そして場合によってはメトリクスの管理方法を理解するだけでよくなりました。
これで、責任の分離という考え方が生まれました。PlatformチームがすべてのドメインリソースとSubscriptionルールを管理し、スキーマやバージョニングの進化に対処するのを支援します。Subscriptionルールは、特定のSubscriberがどのイベントをSubscribeしたいかを定義するものだということを覚えておいてください。これがドメインの観点からPlatformがどのように支援できるかということです。
中央アカウントだけでなく、Subscriberのアカウントでも、ドメイン識別子やドメインEvent Bus、その統合のためのDead Letter Queue、そしてSchema Registryが利用可能であることを確認する能力が必要です。これらの中央集権的なリソースを管理することで、アプリケーションチームの負担を軽減できます。また、開発チームがイベントを自分のアカウントに届ける方法をコントロールする必要がなくなるため、セキュリティとイベントストリームの整合性の向上にも役立ちます。
これは、イベントのSubscribeやUnsubscribeを可能にするAPIを提供することで、Platformを通じて完全に管理することができます。これにより、どのEvent BusにどのようなSubscriptionルールを配置するかを決定できます。また、管理しているイベントの特定のスキーマに基づいてフィルタリングを制御することもできます。これにより、イベントが各アカウントにどのように配信されるかを検証・管理する、完全に統合されたイベントストリームを実現できます。これは環境の一貫性を確保し、リソース管理などの他の課題に対処する上で重要な要素となります。
全体として、Platform TeamはEventストリームを制御しますが、それらのEventがどのように処理されるかには必ずしも関与しません。それはあくまでもApplication Teamの責任です。Application Teamは、サブスクライブしているEventが自分たちのアカウントに配信されることを知っているだけで、その実現方法とのインターフェースは、Platformが公開するサブスクライブおよびアンサブスクライブのインターフェースを呼び出すことだけです。また、Platformが実際に扱っているものを把握しているため、特定のバージョニングやバージョンアップグレードへの対応も容易になります。Platformはサブスクリプションルールを作成しているため、特定のEventがどのバージョンにサブスクライブされているかを正確に把握でき、これらの接続をすべて含むメタデータデータベースの構築を検討し始めることができます。
これにより、ドキュメントの作成方法についての洞察が得られます。Event Catalogというツールの作者であるDavid Boyneさんは、Eventやイベントストリーム、そしてそれらがシステムの他の部分とどのように動的に接続されているかを視覚的かつ動的に確認するための優れたリソースとなるでしょう。最後に、これらすべてのことは、Platform Engineering Teamが正しいことを行い、Platformとの統合や相互作用に関するガードレールを設定するのに役立つPowertoolsのようなユーティリティを構築することで支援されています。
これらすべては基本的に、リソースの管理方法や管理者について一定の標準化を実現すると同時に、開発チームがEventの処理方法について適切な判断を下すために必要な自律性を提供することを可能にします。これこそが、カスタムEventBridgeがPlatformの一貫性を確立する上で大きな役割を果たすことができる部分であり、それによってビジネスを加速し、正しいことを行い、開発統合チームの障害を取り除き、すべてを完全に自動化して実現可能にすることができます。
以上で終わりとなります。今後もこのテーマについて話し合えることを楽しみにしています。来年に向けていくつかの計画があり、誰かがこれらを実現してくれることを願っています。とりあえず、皆さんの組織で独自のEventフローをどのように構成するかについて考える際の参考になれば幸いです。ご清聴ありがとうございました。
※ こちらの記事は Amazon Bedrock を利用することで全て自動で作成しています。
※ 生成AI記事によるインターネット汚染の懸念を踏まえ、本記事ではセッション動画を情報量をほぼ変化させずに文字と画像に変換することで、できるだけオリジナルコンテンツそのものの価値を維持しつつ、多言語でのAccessibilityやGooglabilityを高められればと考えています。
Discussion