📖

re:Invent 2024: AWSが語るEDAの大規模実装 - EventBridgeの活用法

2024/01/01に公開

はじめに

海外の様々な講演を日本語記事に書き起こすことで、隠れた良質な情報をもっと身近なものに。そんなコンセプトで進める本企画で今回取り上げるプレゼンテーションはこちら!

📖 AWS re:Invent 2024 - Event-driven architectures at scale: Manage millions of events (API307)

この動画では、Event-Driven Architecture(EDA)を大規模に実装する際の重要なポイントについて解説しています。AWSのPrincipal Developer AdvocateのEric JohnsonとServerlessのスペシャリストソリューションアーキテクトのBrian Zambranoが、数百万のイベントを管理するスケールでのEDAの実践的な知見を共有します。EventBridgeでは1秒あたり1億4600万リクエストを処理可能な実績があり、そのスケールでの運用におけるスキーマ管理、バージョニング、Observabilityの実装方法を詳しく説明しています。特に、JSON Schemaを用いたバリデーション、API Gatewayを活用したスキーマ強制、Event Catalogによるドキュメント管理など、具体的な実装パターンが示されています。
https://www.youtube.com/watch?v=dy7UXS7ur14
※ 動画から自動生成した記事になります。誤字脱字や誤った内容が記載される可能性がありますので、正確な情報は動画本編をご覧ください。
※ 画像をクリックすると、動画中の該当シーンに遷移します。

re:Invent 2024関連の書き起こし記事については、こちらのSpreadsheet に情報をまとめています。合わせてご確認ください!

本編

Event-Driven Architecture (EDA)の紹介と本セッションの概要

こんにちは。みなさん、いかがお過ごしでしょうか?皆さんの姿が見えないので、声を出していただけますか?あ、聞こえました。私はEric Johnsonです。AWSのPrincipal Developer Advocateを務めています。本日は、私の友人のBrianをご紹介できることを大変嬉しく思います。

皆様、こんにちは。お招きいただき、ありがとうございます。Ericと一緒にこのトークができることを大変楽しみにしています。私はBrian Zambranoと申します。Serverlessのスペシャリストソリューションアーキテクトとして働いています。今日は皆様とお話できることを楽しみにしています。私たち二人ともEDAオタクなんです。EDAについてご存じない方のために申し上げますと、Event-Driven Architectureの略です。私たちはこの分野が大好きで、共有することも大好きです。本日は、数百万のイベントを管理するスケールでのEvent-Driven Architectureについてお話しさせていただきます。

では始める前に、いくつかのガイドラインについてご説明させていただきます。まず1つ目は、これは私が望む任意の数字になります。7とか20とか、何でも良いんです。よくレストランで10人用のテーブルを予約して、一人でバーに座ったりします。2つ目のルールは、これらは引用符であってアポストロフィではありません。なぜならこれは見た目が良くないからです。最後のルールは、これらは親指です。もしこれが気になる方がいらっしゃっても、私は全く気にしません。お気づきかもしれませんが、Brianと私は双子のようなものです。ただし、彼には親指があります。

スケールとEDAの定義:数百万のイベントを管理する

それでは、今日お話しする内容に入っていきましょう。スケールとは何か、EDAとは何か、イベントスキーマの強制と進化、イベントスキーマの管理と発見可能性、可観測性について話し、そして最後にまとめを行います。スケールについて考えるとき、私たちはトラフィックについて考えます。スタートアップを運営している場合、急速な成長を期待していることでしょう。AWSで運用する場合、トラフィックを処理するための強力なサービスが多数用意されています。

興味深い統計をご紹介しましょう:Prime Day 2024では、DynamoDBのピーク時に1秒あたり1億4600万リクエストを処理しました。Prime Dayについてご存じない方のために説明しますと、amazon.comというスタートアップ企業が実施しているセールです。AWS Lambdaは、Prime Day期間中に1.3兆回以上の呼び出しを処理し、毎月数十兆件のリクエストを処理しています。大規模なアプリケーションを構築する場合、ServerlessとAWSが最適な選択肢となりますが、今日はこの話題については触れません。

スケールに関してもう一つ話題にしたいのは、アーキテクチャとそれを管理するチームについてです。これを見てみると、成功しているEvent-Driven Architecture(EDA)はシンプルには見えません。実際にはもっと複雑で、チームが至る所に、世界中に散らばっています。タイムゾーンの違いや、言語の違いなど、管理すべき要素が多くあります。今回はチームについては詳しく触れませんが、飛び交っているこのものに焦点を当てていきます。

私たちが注目するのはEventです。なぜなら、Event-Driven Architectureを考えるとき、すべてはEventを中心に回っているからです。Event-Driven ArchitectureにおいてEventの健全性は、アプリケーションの成功に不可欠です。優れたEvent-Driven Architectureは、飛び交うEventに依存する疎結合なアーキテクチャであり、もしそれらのEventに問題が生じれば、アプリケーションも同様に問題を抱えることになります。

この講演は、そのEventの健全性、スキーマの健全性、そしてそれらをどう扱うかについてのものです。これまでEDAについて話してきましたが、ここでEDAを定義しましょう。正直に言って、これがおそらく今回の講演で最も技術的な部分になります。もし何かメモを取るなら、今がその時です。というのも、これは本当に重要だからです。私はEvent-Driven Architectureをこのように定義します:何かが起こり、それに反応する。これは単純ですが、これこそがEvent-Driven Architectureなのです。アプリケーションは、発生するEventとそれが伝播することに依存しています。

では、Eventとは具体的にどのようなものでしょうか?Eventとは、何かが起きた、またはシステムの状態が変化したことを示すシグナルです。Eventは過去に発生したもので、あるべき姿ではなく、実際に起きたことを示します。Eventは変更できず、不変です。過去に起きたことを変更することはできませんが、それを上書きする新しいEventを追加することはできます。Eventスキーマは、プロデューサーとコンシューマーの間の契約です。これは非常に重要です。APIを使用する際には契約があり、APIは何を送信すべきか、それに対してどう応答するかを指定します。Event-Driven Architectureでも同じです。

プロデューサーがEventを送信する際、コンシューマーは特定のフォーマットを期待します。ここに例があります:ソースはPizza Nutのservice.com、注文が作成されました。注文の内容は「パイナップル抜きピザ」で、これは完璧なピザです。food、proper pizza、pickup、といった情報が見えます。これがEventです - メタデータと実際のデータ自体、チャネルIDなどの情報を提供します。このように、EDAを定義し、それがEventに依存することを説明し、Eventがどのようなものかを見てきました。

イベントスキーマの強制と進化:JSON Schemaとバリデーション

私はこれまで約2年半、イベント駆動アーキテクチャに携わってきました。ここでお話しする内容は、お客様との対話の中で繰り返し出てきた質問から得られた知見です。実際、これらのパターンの中には現場から生まれたものもあります。詳細に入る前に、イベント駆動アーキテクチャの構成要素について整理しておきましょう。まず、データプロデューサーがあります。これはイベントを生成するシステム、つまりビジネスに関連するイベントを発行するアプリケーションや、時間ベースのトリガーなど、あらゆるものを指します。右側にはデータコンシューマーがあり、これらはイベントを受信または取得して処理を行うシステムです。そして中央には、メッセージングブローカーであるブローカーが位置しています。

これらが基本的なコンポーネントで、このトーク全体を通じて触れていきます。イベントブローカーには、大きく2つのカテゴリーがあります。1つ目はプルベースのブローカーで、これにはあらゆる種類のキューイング技術が含まれます。RabbitMQやSQSなど、長年使われてきて馴染みのある技術です。これらはプルベースの技術で、メッセージがブローカーに置かれ、コンシューマーがデータを取得し、ダウンロードして処理を行う必要があります。

プルベースのカテゴリーには、キューの他にストリームがあります。これにはKafka、Kinesis、MSK(Kafkaのマネージドバージョン)などが含まれます。ここでも大きな特徴は、コンシューマーがデータを取得して処理する必要があるプルベースの技術だということです。もう一つのカテゴリーは、プッシュベースのシステムで、私たちの世界ではEventBridgeやSNSがこれに該当します。これらは大きく異なり、メッセージが実際にコンシューマーに配信されます。Lambda関数やAPIなどのコンシューマーは、何もしなくても自動的にメッセージを受け取ることができます。

よく「EventBridgeとKafka、どちらを使うべきか」という質問を受けます。私はいつも、これらは全く異なる技術だと説明することから始めます。なぜなら、メッセージやコンシューマーとのやり取りの方法が異なるからです。一方はプルベースで、もう一方はプッシュベースのシステムです。この講演では主にEventBridgeについて話しますが、これらの内容が異なる場合は、その都度指摘します。ただし、これらのパターンや概念は、基本的にどのブローカーを使用する場合でも適用できます。

Ericが疎結合について触れましたが、現代のほとんどのブローカーでは、左側にペイロードとスキーマを持つプロデューサーがいます。プロデューサーはコンシューマーに配信したいペイロードを持っており、それをブローカーにプッシュします。ブローカーは、それが何であれ喜んで受け入れ、プッシュベースシステムの場合はコンシューマーに配信し、プルベースシステムの場合はコンシューマーがそれを取得します。

しかし、Payloadの一部が変更された場合はどうなるでしょうか?ここで注目すべきは、Order IDが文字列で、電話番号も文字列であるということです。これが少し変更されると、Orderは文字列からネストされたオブジェクトに変わり、電話番号は文字列からnull値に変わります。nullか文字列かを受け入れるのは比較的簡単ですが、文字列からオブジェクトへの変更はかなり大きな変更です。通常、Event Brokerはこれをブローカーに転送する際に問題なく受け入れます。しかし、Consumerはこのことを知っているか、両方のバージョンのPayloadを処理するためのロジックを持っている必要があります。この場合、おそらくConsumerが破綻して例外をスローすることになるでしょう。

Event-Driven Architectureを使用したい理由として、完全なデカップリングを実現したいという声をよく耳にしますが、それは正確ではありません。確かにルースカップリングは実現できますが、それは全くカップリングがないということではありません。ProducerとConsumerの間でEventをパブリッシュする場合、直接通信はしていないという意味でルースカップリングされていますが、Eventをパブリッシュし始めた時点で暗黙の契約が存在します。Payloadのちょっとした変更でConsumerを破壊してしまう可能性は依然としてあり、大規模な環境では、存在すら把握していない何百、何千ものConsumerが存在する可能性があります。

インドやオーストラリア、北米など、異なる地域にいる他のチームが誰がEventを消費しているのか把握できていないというお客様と仕事をしたことがあります。Producerとして変更を加えた際に、その存在すら知らないチームのシステムを壊してしまう可能性があるのです。これは、Eventを消費する人の数という意味でのスケールにおいて問題となります。この問題を解決するためのオプションを整理すると、まず基本的なものとして「約束」があります。つまり、Producerが適切にフォーマットされたPayloadを公開し、誰も壊さないように約束するというものです。

これから詳細に入っていきますが、これが一つの解決方法です。Producer側で対処することができます。真ん中のBrokerレベルでは、強制的な対応が可能です。この時点で、Brokerはトラフィックコップのような役割を果たします。適切にフォーマットされたPayloadの場合、Event BrokerはそのPayloadを通過させ、最終的なConsumerに公開します。無効なものの場合、Event Brokerはそれを拒否し、与えられたものが適切にフォーマットされていないため受け入れられないという通知をProducerに返します。

Event Brokerは今や、有効なEventと無効なEventの交通整理役あるいは調停者となります。もう一つの方法は、アプリケーションレベルでのバリデーションです。Consumerは自身でEventを受け入れ、何らかのスキーマバリデーションを行い、それに応じて処理を行います。これは規模が大きくなると問題になる可能性があります。なぜなら、すべてのConsumerがこれを行う必要があるからです。解決策や詳細に入る前に、JSON Schemaについて説明したいと思います。JSON Schemaをご存じない方のために説明すると、これはJSONのPayloadを定義し、実際に強制または検証することができる定義です。

スキーマ管理とバージョニング:変更への対応

ここでは、ペットに関する非常にシンプルなオブジェクトを見ていきます。とても読みやすい構造になっています。プロパティには整数型のID、有効な値が列挙された文字列型のtype、そして25から500の間でなければならない数値型のpriceが含まれています。JSON Schemaは、JSONペイロードを検証するためのツールです。多くの問題を解決できますが、すべての問題を解決できるわけではないことに注意してください。例えば、「もし犬なら、価格はこれで、そうでなければそれ」というような条件付けはできませんが、スキーマ管理において人々が直面する多くの課題を解決してくれます。

最初に考えられるのは、ペイロードの検証をエッジに押し出すことです。このダイアグラムが示しているのは、Producerが中央リポジトリにアクセスできるということです。これは、おそらくバージョン管理され、ProducerとConsumerの両方がアクセスできる場所に配置される共有ライブラリとなり、それをダウンロードしてペイロードを検証することができます。素晴らしい点は、これをJSON Schemaで行うことも、Protocol Bufferのような別の方法を使うこともできるということです。スキーマ検証に使いたい仕組みを選んで使用できます。

先ほど述べたように、これはProducerとConsumer双方が共有ライブラリを通じてアクセスできます。Producerの場合は公開前に、Consumerの場合はイベントを受信する際に検証を行います。もし私が今これから始めるとしたら、おそらくここから始めるでしょう。というのも、かなりシンプルで、動く部分が少なく、インフラを管理する必要もなく、理解しやすいモデルだからです。ただし、スケールする際の課題として、すべてのチームにこの方法を採用してもらう必要があります。

では、スキーマ強制の異なるモデルを見てみましょう。この例では、EventBridgeに話を戻します。EventBridgeでは、Producerは通常、Put Eventsと呼ばれるAPIを使用してイベントを公開します。任意のJSONペイロードを公開できます。ここでの変更点は、EventBridgeに直接公開するのではなく、API Gatewayを通じてイベントを公開できるということです。API Gatewayには、特定のエンドポイントに対するJSON Schema定義である「API Gatewayモデル」という機能があります。API Gatewayに到着したイベントの場合、検証を代行してくれます。JSON Schemaを参照し、ペイロードが期待されるスキーマと一致しない場合、それを拒否してAPI Gatewayからエラーコードが返されます。ここではAPI Gatewayを交通整理係として活用しています。有効なペイロードの場合、API Gatewayは「OK」と応答し、受領と検証のチェックを確認します。

API GatewayにEventBridgeのイベントバスにそのイベントを転送させ、通常通りEventBridgeからすべてのConsumerにプッシュすることができます。

実際の動作の様子をコンソールのスクリーンショットでお見せしましょう。本番環境では、これをInfrastructure as Codeで実装することになります。コンソールのMethod Requestセクションの下部に、Request Bodyという項目があります。ここでは特定のContent Type(この場合はapplication/JSON)に対して、モデルを参照することができます。今回の例では、先ほどお見せしたPetモデルを使用しています。HTTPリクエストが行われると、API Gatewayが自動的にバリデーションを実行し、一致しない場合はリクエストを拒否します。

ペイロードのバリデーションが成功すると、Integration Requestに進みます。Integration Requestでは、API GatewayがEventBridgeのEvent Busにイベントを転送するよう設定できます。下の部分にあるのがVTLコードです。VTLコードは初心者には少し難しいかもしれませんが、一度動作するようになれば安定して機能します。コードの下から2行目を見ると、event bus nameという項目があり、これがAPI Gatewayがイベントを転送する先のEvent Busになります。私はこれをInfrastructure as Codeで実装することができ、詳しい解説のブログ記事と社内のGitリポジトリも用意しています。

組織によって要件は異なり、トラフィック制御パターンやバリデーションを前後両方で実装したいというお客様もいます。JSONスキーマのバリデーションはエッジで実行することが可能です。API Gatewayに保存されているモデルを最初のバージョンと同様にフェッチし、API Gatewayにイベントをパブリッシュする前にバリデーションを行うことができます。コンシューマー側でも、API Gatewayのモデルを取得して受信側でバリデーションを実行できます。

大規模な環境では、モデルを取得するためのAPI呼び出しは避けたいところです。そのため、モデルをAmazon S3バケットなどに保存し、キャッシングを実装することをお勧めします。この場合、プロデューサーはS3からスキーマを取得してローカルにキャッシュし、パブリッシュ前にバリデーションを実行します。このようなモデルでは、API Gatewayにデプロイされるモデルを同期し、プロデューサーやコンシューマーがダウンロードできるようにする、比較的複雑なCI/CDパターンが必要になります。

バリデーション自体は複雑ではありません。JSONスキーマで動作し、Protocol Buffersなど他の方式でも同様です。このシンプルなPythonコードで、モデルのフェッチ、ダウンロード、バリデーションの方法をお見せします。まず、Boto3を使用してAPI Gatewayリソースを作成します。モデルを取得するには、API IDとモデル名を指定する必要があります。モデルを取得すると、先ほどお見せしたJSONブロブであるスキーマが得られます。クライアントサイドまたはコンシューマー側でJSONスキーマのバリデーションを行うのは、たった1回のAPI呼び出しで済みます。

では、これらをどのように実施するかを理解したところで、変更が発生した場合について考えてみましょう。時間の経過とともにスキーマは進化し、新しいフィールドが追加されたり、古いものが非推奨になったり、スキーマの形が変化したりします。では、バージョニングにはどのように対処すればよいのでしょうか?これは、ID、タイプ、そしてAdoptionビューを持つイベントです。このように単純なイベントを扱っている人はいるでしょうか?おそらく誰もいないでしょう。これは、ビジネスイベントと呼べるものです。

イベントスキーマの管理と発見可能性:ツールとテクニック

私たちが推奨するのは、実際のペイロード、つまりビジネスデータを、Detailなど任意の名前を付けたネストされたフィールドにラップすることです。その理由は、データに関するデータであるメタデータの公開も推奨しているからです。Detailフィールドはアプリケーション、開発者、またはエンドユーザーが関心を持つ実際のペイロードをラップし、メタデータフィールドは他のすべてのデータをラップします。後ほど、ここにすべてのバージョンデータをラップする方法をお見せします。

イベント駆動アーキテクチャの良き実践者として、分散トレーシングに使用するCorrelation IDがあります。また、同じイベントが複数回発生した場合でも1回だけ処理できるようにするためのIdempotency Keyもあります。そして、バージョニングに関連する新しいフィールドがあります。最初のフィールドは文字通りVersionで、このイベントがバージョン1であることを示し、Detailにはバージョン1のイベントを表すすべてのペイロードが含まれています。さらに、プロデューサーやコンシューマーがDetailフィールドにラップされたペイロードを検証するためにダウンロードして使用できるスキーマがあります。

これはとてもシンプルですが、変更が発生し、スキーマの新しいバージョンが登場した場合はどうなるでしょうか?ここにはTTLと呼ばれる2つのフィールドがあります(名前は任意です)。TTLは、このスキーマのバージョンが期限切れになる時期と、次のバージョンが何になるかを示します。これらの値が両方ともnullの場合、現在見ているバージョンは無期限に有効です。まだバージョン2は存在していません。

バージョン2が登場すると、状況が変わります。TTLはnull値から実際のタイムスタンプに変わります。これは、Detailで公開しているこのバージョンがいつ期限切れになるかを示しています。ここでは4月1日という日付を例として挙げました。プロデューサーとしてこれを公開する場合、このバージョンは4月1日までに廃止されることをすべてのクライアントに伝えることになります。組織の状況に応じて、この期間はできるだけ長く設定すべきです。10年は長すぎますが、移行に時間がかかる場合は1年程度でも構いません。次のバージョンはバージョン2で、ダウンロード可能なスキーマがあり、それを使用して次のバージョンをダウンロード、確認、検証することができます。

Version 1とVersion 2の準備ができている場合、どのような選択肢があるでしょうか?どのようにしてユーザーをオンボーディングさせればよいのでしょうか?答えは、ダブルパブリッシングが必要だということです。新しいバージョンができた場合、プロデューサーはTTLが期限切れになるまでVersion 1を公開し続け、同時にVersion 2も公開して、コンシューマーが新しいスキーマバージョンにオンボーディングできるようにする必要があります。

スキーマの強制とバージョニングの観点からスキーマ管理について説明してきましたが、ここからはEricに戻って、これらのスキーマとイベントをカタログ化し管理する方法について説明してもらいます。Event-Driven Architecture(EDA)は決して新しいものではありませんが、現在大きな注目を集めています。長い間存在してきたもので、AWSが発明したわけではありません(時々私が功績を主張することはありますが)。ただし、EventBridgeやLambda functionsのようなサービスで、より簡単に実現できるようになりました。現在、これらのイベントやスキーマをどのように管理し、ドキュメント化し、ガバナンスを行うかについて、エコシステムが形成されつつあります。

まず最初はインフラストラクチャーガバナンスです。基本的に、すでにテストと検証を済ませたデプロイ可能なリソースを提供することを意味します。これが機能すると確認できたものを、CloudFormation、Terraform、CDKなどの形で提供します。これにより、イベント構造をインフラストラクチャーの観点から制御できます - 何を出力し、何を受け入れるかといったことです。これは、コンシューマーとプロデューサーの両方を管理できる、エンドツーエンドでコントロールできる場合に最も効果的です。

このためのネイティブサービスの1つがAWS Service Catalogです。これを使用すると、デプロイしたいAPIエンドポイント、Lambdaの動作方法、イベントスキーマの仕組みなど、サービスのライブラリを構築できます。これらをデプロイでき、ご覧のように異なるポートフォリオを構築でき、そこから組み込まれた異なる製品を構築できます。このサービスでできることは多岐にわたります。

現場で大きな注目を集めているもう1つがBackstageです。これは私の親友のDavid Andersonがよく話題にするものです。David Andersonは「Creating the Flywheel Effect」の著者で、サービスコミュニティやEvent-Driven Architectureコミュニティでよく知られています。彼の会社では、顧客がこれを構築するのを支援しています。主なアイデアは、開発者に開始点を提供することです。新しい会社に入社した開発者は、「はい、これがあなたのマシンです。あとはよろしく」と言われることが多く、どこから始めればいいのか把握するのが大変です。これは、その開始点を提供し、設定や構築を行えるようにするものです。

次に、私たちがこれを管理する際に注目するのは、スキーマディスカバリーです。素晴らしい点の1つは、ドキュメント化、バージョン管理、マッピングができることです。EventBridge Schema Registryは本当に優れていて、EventBridgeを通過するイベントの形式を実際に把握することができます。多くの場合、どのようなイベントが入ってくるのか、どのような形式なのかわからない時に、これを確認することができます。さらに素晴らしいのは、イベントを詳しく調べてその形式を確認し、コードバインディングをダウンロードすることもできる点です。これにより、開発者は何を期待すべきかを知ることができます。

ツールを使用することは非常に重要です。私たちはドキュメントやRunbookなどを書くのが好きですが、それらは古くなってしまいます。Amazonには社内Wikiが多数ありますが、非常に役立つ一方で、もはや意味をなさない古いページもあります。自動化されていないドキュメントの管理は大変なので、自動化のためにツールを使用しましょう。サードパーティの分野では、AsyncAPIというものもあります。API GatewayのOpenAPIをご存知の方なら、AsyncAPIは同様のことを目指しています。これを使ってドキュメント化し、情報を入力すると、テストのようなものが構築されます。

最後に紹介するのは、以前AWSのDeveloper Advocateだったデビッド・ボインが開発したEvent Catalogです。多くの大企業がこれを使用しています。Event Catalogの考え方は、イベントをドキュメント化することです。このサービスが作成するイベントはこれで、このサービスが受け取るイベントはこれだと指定できます。ここで見ているのは、Serverless Espressoの始まりのような部分です。私たちのチームがこれを作成し、2021年以降毎年re:Inventに持ち込んでいます。これがそのイベントの形式で、これがデビッドが構築を進めてきたものです。ここでの考え方は、これをドキュメント化することで、アプリケーションの一部としてWebサイトを持つことができるということです。

ダウンロードしてインストールして実行すると、変更するたびにビルドとデプロイが行われ、新しいアプリが作成されます。これにより、開発者は常にフローがどのようになっているか、イベントがどのように流れているかを確認することができます。Event-driven Architectureの現実は複雑です。一般的に開発の現実も複雑です。これらのツールを使用してそれらを管理し、しっかりと把握できるようになると、非常に有益です。

Event Catalogでは、Order Processorとそこから発生するイベントを見ることができます。パブリッシュされているすべてのものを確認でき、Config Changesの詳細を掘り下げることができます。素晴らしいのは、EventBridge Schema RegistryやApache Kafkaと連携することです。誰かがApache Kafkaを使用している場合、Event Schema Registryがあり、これらを取り込んで構築することができます。開発者がものごとの流れを理解するのを助けるためにできることが多ければ多いほど良いのです。チームがEvent Catalogやその他のツールを使用してイベントストーミングを行ったり、それらを構築したりしているのを見かけます。コードを1行も書く前に、イベントがどのように流れるかを確認することができます。

実は、これは私たちがいくつかのサービスを再構築する際に取り組んでいることの一つです。今、これをマッピングしていこうとしています。基本的にはEvent-driven開発ですね。これは単なる一例で、他にもたくさんの方法があります。決して網羅的なリストではありませんが、このような開発手法を取り巻くコミュニティが成長しています。開発者の皆さんには、独自のシステムを構築するのではなく、これらのツールを活用することを強くお勧めします。

Observability:EDAにおける監視と問題検出

さて、これについて学んでいただいたところで、次にすべきこと - 実際これは最初に考えるべきことなのですが - Brianに代わってObservabilityについてお話ししたいと思います。Observabilityは、独立したシステムが連携して動作し、すべての健全性を把握する必要があるため、大規模な環境では実現が困難です。EventBridgeに特有のいくつかの点について説明し、その後、Consumerとその動作を把握するためのテクニックについて説明していきます。

私の考え方としては、まず比較的監視が容易なProducerの健全性があります。個々のアプリケーションにログやモニタリングを組み込む方法は、私たちみんな知っていますよね。次にConsumerの健全性があり、これはLambda関数やコンテナかもしれません。そして、それらのメッセージを仲介するBrokerの健全性、最後にシステム全体のエンドツーエンドの健全性があります。特に、複数のホップを経由して一つのシステムから別のシステムへと進む場合、ここが複雑になる可能性があります。AWSと共有責任モデルについて考えると、EventBridgeを使用する場合、Event Busの健全性については私たちがカバーしています。EventBridgeは私たちが運用する大規模なマルチテナントシステムで、サービスチームが常にシステムが正常に動作するよう監視しています。

デカップルされたコンポーネントと疎結合のProducerとConsumerを持つシステムが正しく動作していても、ProducerはどうやってConsumerが健全であることを知るのでしょうか?Consumerで何が起きているのでしょうか?イベントはConsumerによって消費されているのでしょうか?どのくらい時間がかかっているのでしょうか?SNSなどの特定のサービスが遅いと言われることがよくありますが、この点についてもう少し詳しく見ていきましょう。

EventBridgeについて - この説明に入る前に、Ericが言及したように、私たちは双子のようなものです。二人とも禿げていて、二人ともAWSが大好きです。私は彼ほど面白くないですが、おそらくこれらのメトリクスについて何度もつまずくと思います。名前が長すぎるので。あらかじめご了承ください。Producerとして、EventBridgeを監視する際にいくつかのメトリクスを使用できます。これらはすべて、アプリケーションの動作を示すカウントメトリクスです。Invocation attemptsはEventBridgeにイベントをパブリッシュしようとした回数を示し、Successful invocation attemptsは実際に成功した回数を示し、Retriesは複数回再試行した回数を示します。

メトリクスを見て可観測性について考える際は、操作可能な次元についても考慮してください。これはルール名で実行できます。私たちは1つのルールにつき1つのターゲットを持つことを推奨しています。単一のEvent Busに対して集計することもできます。これらは数値なので、正常な呼び出しの割合など、パーセンテージで考えることもできます。そのためにCloudWatchとMetric Mathを使用できます。成功呼び出し率は、正常にパブリッシュされたイベント数を、呼び出し試行の総数で割ったものです。理想的には、これらは同じになるはずです - つまり試行の100%が成功することを目指します。

失敗に関しては、ルール名を次元とする3つのメトリクスを挙げています。これらも数値です:失敗した呼び出し、Dead Letter Queueに送信された呼び出し、Dead Letter Queueへの配信に失敗したメッセージです。理想的には、これらすべてがゼロであることが望ましいです。実際の環境では異なりますが、これらは監視すべき項目です。EventBridgeは、デフォルトで失敗した場合、24時間以内に最大185回まで配信を再試行します。EventBridgeがイベントを受け取った後は、そのイベントは安全です - 配信されるか、設定したDead Letter Queueにドロップされるかのいずれかで、イベントが失われることはありません。

レイテンシーに関しては、イベントのパブリッシュから消費者が受信して処理するまでの時間を測定します。長い名前を持つ3つのメトリクスがあります:取り込みから呼び出しまでのレイテンシー(完了レイテンシー、成功レイテンシー、開始レイテンシーを含む)です。開始レイテンシーは、EventBridgeがイベントを受信してからターゲットの呼び出しを開始するまでの時間を測定します。これは消費者が実際に受信して何かを行ったということではなく、消費者がそのメッセージを正常に受け入れただけの状態です。完了レイテンシーは、EventBridgeがイベントをパブリッシュしてから消費者が受信して処理するまでの時間です。ここでの処理は、成功した処理か失敗した処理かは関係ありません。これは最初のパブリッシュからその結果(肯定的か否定的かに関わらず)までの時間です。

最後のメトリクスは、取り込みから呼び出し成功までのレイテンシーです。これは、EventBridgeがイベントをパブリッシュする時点から、配信が成功するまでの時間を測定します。この場合、グラフィックは消費者にパブリッシュされたイベントが2回失敗し、3回目で成功したというシナリオを示しています。このメトリクスは、開始時点から最後の成功完了までの時間を示します。これにはすべての再試行が含まれます。

この最初の部分、つまりEventBridgeへのパブリッシュの測定は、皆さんの責任となります。EventBridgeへのパブリッシュが遅いと言う顧客と話したことがありますが、これについては慎重に考える必要があります。特にイベント駆動アーキテクチャでは、その間に多くのことが起こるため、単に何かをパブリッシュして遅いと結論付けることはできません。そのため、EventBridgeが遅いと言う前に、これを非常に細かく、きめ細かく測定することを考えてください。レイテンシーの問題に気付いた場合は、それがどこで発生しているのかを把握してください。

消費者側で問題が発生した場合はどうなるのでしょうか?メッセージを発行したものの、Consumerで問題が発生した場合、どのようにその情報をProducerに伝えればよいのでしょうか?顧客から、発行した全てのEventがConsumerによって正常に処理されたことを確認したいという要望を聞いたことがあります。ただし、このようなモデルを考え始めると、それは同期型のモデルを説明していることになるので、注意が必要です。もし本当にそれが必要な場合は、REST APIを使用した同期処理に戻ることをお勧めします。とはいえ、Consumerに問題が発生していることを把握することで、必要な情報を得ることは可能です。私たちは、問題がないことを示すサインとして「沈黙」を前提とすることができます。

Consumerが問題を報告し、その詳細を提供できるようなパターンを検討してみましょう。最初に思いつくのは、Producer側にAPIを立ち上げ、ConsumerがHTTP POSTを通じて問題を報告できるようにすることかもしれません。しかし、スケールが大きくなると、自身にDOS攻撃をしているような状況に陥る可能性があります。そして、また同期モデルに戻ってしまいます。Event-Driven Architectureを採用するのであれば、非同期通信を本気で取り入れることをお勧めします。

そのアプローチではなく、より良い方法は、Consumerが自身の経験している問題の詳細を含むEventを発行できる仕組みを提供することです。そうすれば、Producerはそれを確認し、Eventを受け取って対応することができます。おそらくProducerがSchemaを壊してしまい、考慮していなかった状況が発生したのかもしれません。Consumerは自身のEventを発行する仕組みを持つことになります。私は、Producer向けの別のEvent Busを用意し、そこでProducerがClientが経験しているエラーについて、CloudWatch Eventの作成や独自のメトリクスの発行といったアクションを起こすことをお勧めします。

Datadogやその他のパートナーのような中央モニタリングツールを使用している場合、ある意味でこれは簡単になります。なぜなら、Producerは中央プラットフォームに投入されたメトリクスをモニタリングし、ConsumerはそのプラットフォームにEventやメトリクスを発行できるからです。考え方は同じですが、メトリクスが集まる場所があることで、双方向のコミュニケーションが可能になります。ここでの重要なポイントは、Consumerがどのような課題を抱えているかをProducerが知る方法を提供することです。以上で多くの内容を説明しました。残り数分ですので、Ericに締めくくりをお願いしたいと思います。ありがとう、Brian。そうですね、私たちは多くの内容を説明してきました。Observabilityは非常に重要です。私は企業と仕事をする中で、「アプリケーションの観測に何をしていますか?」と尋ねると、「たくさんのログを保存しています」と答えることがあります。

まとめと今後の学習リソース

それらのログで何をしているのですか?ログからストーリーを読み取れていますか?私は、最初からObservabilityについて考えることを強くお勧めします。ログを書き、メトリクスを構築してください。IaCでメトリクスを実装することもできます。アプリケーションが稼働していて、その運用にお金を使っているのであれば、そのストーリーを知り、何が起きているのかを理解したいはずです。Observabilityは非常に重要なのです。

この内容が皆様のお役に立てば幸いです。スケールについてお話しする際、おそらく皆様が想像されていたものとは異なるかもしれませんが、多くの方々が見落としがちで、アプリケーション構築時に頭を悩ませることになるスケールについてお話ししました。この内容が参考になれば幸いです。ここで重要なポイントをいくつかご紹介させていただきます。1つ目は、EDAで構築し、できる限りカップリングを減らすこと。2つ目は、スキーマを強制すること。信頼だけに頼らず、信頼しつつ検証することです。Eventとそのイベントの進化に関する計画を理解すること。計画を立て、Event Sourcingやこれらの計画を支援するツールを検討し、モニタリングすることで、後々の複雑さを軽減できます。そして、Observabilityを念頭に置いて始めることです。

このQRコード、この短いリンク、この12d.comで、多くのリソースをまとめています。これはすべてAPI GatewayとDynamoDBをVTLで構築しています。これを構築した時、VTLは心臓の弱い人向けではないと言いましたが、確かに機能します。ぜひ学習を続けることをお勧めします。ここにいくつかのリンクがあります。バッジを取得することができ、その他にもいくつかの参考になるセッションがあります。月曜日のセッションはすでに終了していますが、録画されていますので、後ほどご覧いただけると思います。

明日は、Amazon ECSとAWS Fargateを使用したEvent-Driven Architectureの構築についてのセッションがあります。これは私のセッションなので恥ずかしながら宣伝させていただきます。EDAについて詳しくお話しする予定です。そして水曜日には、Event-Driven Architectureを使用したMicroservicesの最新化についてのセッションがあります。これらもぜひチェックしてください。もちろん、今週の残りの予定が空いているとは限りませんが。Brian、参加させていただき、ありがとうございました。とても楽しかったです。皆様には感謝申し上げます。様々な選択肢がある中、お時間を割いていただき、ありがとうございました。アンケートにご協力いただき、フィードバックをお聞かせください。良い一日をお過ごしください。ありがとうございました。


※ こちらの記事は Amazon Bedrock を利用することで全て自動で作成しています。
※ 生成AI記事によるインターネット汚染の懸念を踏まえ、本記事ではセッション動画を情報量をほぼ変化させずに文字と画像に変換することで、できるだけオリジナルコンテンツそのものの価値を維持しつつ、多言語でのAccessibilityやGooglabilityを高められればと考えています。

Discussion