Introduction to event-driven architectureの翻訳です。
2021年8月18日
イベント駆動型アーキテクチャ入門
さようならリクエスト・レスポンス、ようこそプロデューサーとコンシューマー!マイクロサービス・アプリケーションを構築する最良の方法であるイベント駆動型アーキテクチャを発見するために、ぜひお読みください。
リクエスト・レスポンスは、コンピューティングやほとんどのウェブアプリケーションで使われる伝統的なコミュニケーションパターンです。ウェブサービスでは、クライアントが同期HTTPリクエストを行い、ウェブサーバーからのレスポンスを待つのが標準的なアプローチです。マイクロサービス・アーキテクチャでは、リクエスト・レスポンスもよく使われる。ウェブサーバがデータベースに接続リクエストやクエリを送信し、レスポンスを待つ。多くのユースケースでは、このパターン(同期的なリクエストとレスポンスの連鎖)はうまく機能する。そうでなくなるまでは。
チェーンの1つのリンクがダウンするとどうなるか?応答を待っているリクエストはまったく応答を受け取らない。待ち続けるか、タイムアウトする。アプリケーション全体がブロックされてしまうのだ。さらに、サービスの数が増えれば増えるほど、サービス間の同期インタラクションの数も増える。このような状況では、1つのシステムのダウンタイムが他のシステムの可用性にも影響する。
別のアプローチとして、イベント駆動型アーキテクチャ(EDA)上にマイクロサービス・アプリケーションを構築する方法がある。イベント駆動型アーキテクチャは、非同期にイベントを処理する、プロデューサとコンシューマという、分離された**コンポーネントで構成されており、多くの場合、ブローカと呼ばれる仲介者を介して動作する。というと、なんだか難しく感じるかもしれない。ご心配なく。これらのコンセプトを一歩ずつ説明していきます。この記事では、イベントドリブンアーキテクチャを構成するコンポーネント、このパラダイムを使う理由、そして実装方法について見ていきます。
この記事では、イベントドリブンアーキテクチャがどのようなもので、どのようにすればあなたのために機能させることができるのか、その概要を説明します。以下がその内容です:
コアコンセプト
1.イベント
イベント・ドリブン・アーキテクチャの中心はすべてイベントです。簡単に言えば、イベントとは、アプリケーションで起こる面白いことです。エンドユーザ・クライアント・レベルからネットワーク接続レベルに至るまで、アプリケーションのすべてのレベルでのイベントが注目されるかもしれません。
以下にイベントの例を示します:
- 新規ユーザーがウェブ・アプリケーションでアカウントを作成した。
- HTTP リクエストが、レート制限のしきい値を超えたために API ゲートウェイによって拒否された。
- ウェブ・サーバがリソースを削除するためにデータベースにクエリを送信した。
- API サーバーがキーバリューストアに到達しようとして接続に失敗した場合。
おわかりのように、何がイベントとして適格であるかは、信じられないほど幅広い。
2.イベントの記録
イベントの発生を捕捉する場合、イベントレコードはそのイベントを捕捉するデータである。そのデータには以下のようなものがある:
- リクエストIDまたはヘッダー情報
- 発信元IPアドレス
- クエリーステートメント
- 影響を受けるリソースのID
- タイムスタンプ
- など
イベントレコードの送信者(プロデューサ、これは後で説明する)は、そのイベントがどのように消費されるかを知らないので、そのレコードにどのようなデータを含めるかについて、最善の推測をすることしかできない。時には、必要なのはイベントのパンくずだけである。必要であれば、コンシューマが自分で追加情報を探し出すのに十分な痕跡である。イベントレコードペイロードのデザインは、いくつかの注意深い考察を必要とすることがある。
3.プロデューサーとコンシューマー
様々なサービスを持つイベントドリブンアーキテクチャでは、プロデューサーとコンシューマーがイベントを扱う主要なアクターである。プロデューサーはイベントが発生すると作業に取りかかり、イベントの記録をつなぎ合わせ、その記録をある種のキャプチャに送信する。一方、コンシューマーは、特定のイベントの発生をチェックまたはリッスンし、それらのイベントに応じて対応できるようにする。
4.ストリーム
先ほど、プロデューサーがイベントの記録をある種のキャプチャに送信することを述べた。より正確には、プロデューサーはイベントのレコードをストリームに書き込む。ストリームは、イベント・レコードの永続的で順序付けられたシーケンスである。
イベントが発生すると、プロデューサーはイベントレコードをストリームに送る。コンシューマーはストリームを監視し、ある種のイベントの到着や存在を待つ。
5.非結合コンポーネント
EDAとリクエスト・レスポンス・パターン(コンシューマーはイベントに関する情報をリクエストし、プロデューサーはイベントレコードを書き込むことでイベントの発生に応答する)は類似しているように見えるかもしれないが、EDAではプロデューサーとコンシューマーは高度に分離されている。互いに独立して機能する。
プロデューサーは、イベントのコンシューマーについてまったく知ることなく、イベントを書き込む。実際、プロデューサーはイベントのコンシューマーが存在するかどうかさえまったく知らない。
一方、消費者はイベントが発生したことだけを気にしており、イベント・プロデューサーが誰であるかはまったく知らない。
EDAでは、プロデューサーとコンシューマーは高度に切り離されているため、あるサービスの停止やダウンタイムが他のサービスの可用性に影響することはない。プロデューサは、イベント・コンシューマについて何も知らなければ、単にイベント・レコードを書き込むだけである。イベントのすべてのコンシューマが利用できない場合でも、プロデューサは影響を受けない。同様に、コンシューマーは単に新しいイベントレコードの存在をリッスンす るだけであるが、それらのイベントのプロデューサーがダウンタイムを経験し ても、それ以外は影響を受けない。
6.非同期インタラクション
プロデューサーとコンシューマーは分離されているので、それらの相互作用は非同期である。プロデューサーがイベントレコードをストリームに書き込んだ後、その仕事は終了する。プロデューサは、コンシューマがいつそのイベントレコードで何かを行うか、あるいは、そのイベントで何かが行われるかどうかはまったく気にしない。
非同期インタラクションでは、コンシューマーはストリームからそのイベントを即座に読み取るかもしれないし、負荷に応じて後の段階で読み取るかもしれない。コンシューマーは、集計と分析のために何らかのタスクがスケジューリングされた週の終わりにイベントを読むことさえできる。重要なのはEDAは非同期であるため、サービスは他のサービスからの機能の即時パフォーマンスに依存しない。彼らは自分の仕事をし、生活を続ける。
7.メッセージ・ブローカー
プロデューサーとコンシューマーがEDAの主要なアクターである一方で、イベントストリームの保存と利用可能性を促進するための仲介者も必要です。メッセージ・ブローカーは、イベントの取得、保存、およびコンシューマーへの配信を担当します。メッセージ・ブローカーは信頼性が高く、スケーラブルである必要があり、最も重要なことは、システム障害時にイベントを失うことがないようにすることです。
メッセージ・ブローカーには、データの保存方法によって定義される2つのカテゴリーがあります:
1.1. ストア・バック:これらのブローカーは、コンシューマーにサービスを提供するために、イベントをデータストアに格納する。コンシューマーにイベントを配信した後、スト アからイベントをパージする。RabbitMQとApache ActiveMQがストアバックアップ型ブローカーの例である。
2.ログベース:これらのブローカーはイベントをログに保存する。ブローカーは消費後もイベントを保持する。イベントは削除されないため、ブローカーはコンシューマーが以前の時点からイベントを再生することを可能にする。NATSとApache Kafkaは、このタイプのブローカーの例である。
Apache Kafkaは、最も人気のある耐久性のあるオープンソースのメッセージ・ブローカーの1つで、アプリケーションがイベントやデータのストリームを処理、永続化、再処理できるようにする。Kafkaのアーキテクチャーとルーティングのアプローチについては、次回の連載で詳しく説明する。
前回は、EDAにおけるプロデューサーとコンシューマーが高度に分離されていることを強調した。ここで、プロデューサーとメッセージ・ブローカー、そしてコンシューマーとメッセージ・ブローカーの間には、必要な結合が存在することを指摘しておきます。効果的なEDAシステムは、そのメッセージ・ブローカーがプロデューサーによる書き込みに対して非常に利用可能であることを必要とします。同様に、ストアバックアップとログベースの両方のブローカーは、イベント配信の保証を提供します。
8.イベントスキーマ
イベントスキーマは、EDAにおけるイベントレコードの規定形状である。このイベントスキーマは、システム内のプロデューサとコンシューマの間で合意された契約のように機能する。プロデューサーは、イベント・スキーマの仕様に準拠したイベント・レコードを公開するように設計されており、コンシューマーは、ストリームからイベントを読み込む際に何を期待すればよいかを知ることができる。私たちAivenは、スキーマと関連する変更を追跡するためにKarapaceを開発しました。
イベントを使って状態変化を通知する
EDAの核となる概念を学んだところで、一般的なユースケースとパターンを考えてみよう。
Apache KafkaのようなブローカーはPublish-Subscribeパターンをサポートしており、コンシューマーがブローカーへのメッセージのルーティングを定義する。ルーティングはコンシューマー主導で行われるため、どのコンシューマーもブローカーにプラグインすることができ、他のサービスに影響を与えることなく、興味のあるイベントを受信することができる。
EDAでは、任意のサービスは他のサービスが存在するかどうかを知らない。あるサービスが関心を持つのは、システム内の特定の状態変化だけであり、そのサービスはその変化に反応する。例えば、eコマース・アプリケーションに2つのサービスがあるとしよう:
1.受注サービス:顧客からの注文を受け付ける。
2.出荷サービス:受注した注文を発送する。
顧客が注文をすると、受注サービスはその状態を更新し、"order received "イベントをメッセージブローカーに発行します。配送サービスはそのイベントをフェッチし、状態を更新する。サービス間の疎結合により、既存のサービスを変更することなく、アプリケーションの機能セットを拡張することができます。
例えば、アプリケーションに価格サービスを追加したいとします。このサービスは、需要に基づいて商品の価格を更新する。そして、他のサービスに影響を与えることなく、"order received "イベントのコンシューマとして新しいサービスをプラグインすることができます。
イベントを使って状態を複製する
前の例では、ステートの変更をサービスに通知するためにイベントを使用した。しかし、配送サービスが顧客の詳細を必要とする場合、ある種のカスタマーサービスに同期的に問い合わせる必要がある。勘のいい読者なら、このような同期的なやりとりが、サービス間の緩やかな結合を壊していることに気づくだろう。この問題はイベントで解決できる。
イベントを使用して顧客サービスからステートをレプリケートし、出荷サービスがそのローカル・ステートを使用して顧客の詳細を読み取れるようにします。顧客が配送情報を更新するたびに、"customer data "イベントがメッセージブローカーに発行される。出荷サービスは "顧客データ "イベントにサブスクライブされ、顧客の出荷情報のローカル状態を常に最新に保つことでそれらのイベントに反応します。このパターンは正式にはevent-carried state transferと呼ばれる。
イベント・コラボレーション・パターン
Martin FowlerはEvent Collaborationと呼ばれるパターンを紹介した。これは、一連のサービスが1つのビジネス・ワークフロー上でコラボレーションすることを可能にする。このアーキテクチャでは、各サービスはイベントをリッスンし、新しいイベントを作成することで、ワークフローの中で自分の役割を果たす。イベントは、オペレーションを完了するために、サービスによってオーケストレーションされた方法で処理される。
eコマース・アプリケーションの次の図では、さまざまなサービスとイベントの相互作用から生まれるワークフローを見ることができる。イベントを生成するサービスもあれば、イベントを消費するサービスもある。時には、サービスがイベントを消費し、その後、別のイベントを作成して反応することもあります。イベントは、トピックを使用することで互いに関連付けることができる。
ご覧のように、単一のサービスがプロセスを所有することはなく、各サービスはイベント遷移のサブセットを所有する。各サービスは、自分が必要とするイベントと、自分が生成するイベントのみを理解する。疎結合のおかげで、生成されたイベントスキーマとの互換性を維持する限り、ワークフローに影響を与えることなく、既存のサービスを置き換えたり、より多くのイベントを発生させるためにサービスを更新することができます。
Apache KafkaによるEDAへの移行
Apache Kafkaクラスタは基本的に、クラスタ内の多くのノードにまたがる、メッセージで満たされたログファイルのコレクションである。Kafkaの内部は、これらのログファイルを結び付け、プロデューサとコンシューマ間のメッセージを確実にルーティングし、フォールトトレランスのために複製し、障害を優雅に処理する。Kafkaは、高スループットのストリーミング、耐久性と順序付けされたメッセージ配信、大規模データセットの長期保存など、様々なユースケースに対応するように設計されたメッセージングシステムです。Kafkaは分散型でスケーラブルなメッセージング・サービスであり、サービスがイベントを交換するための理想的なバックボーンとなっている。
イベントベースのアーキテクチャに移行する際、アーキテクチャの変更とインフラ管理を同時に考えるのは大変に思えるかもしれない。Apache Kafkaを使ったEDAの実装に集中するためには、AWS、Azure、GCPのような主要なクラウドプロバイダーでデプロイされホストされているAiven for Apache Kafkaのような、完全に管理されたApache Kafkaソリューションでインフラストラクチャの懸念をオフロードすることができます。
まとめ
この記事では、イベントドリブンアーキテクチャを構成するコアコンセプトについて説明しました。イベント、主なアクター(プロデューサーとコンシューマー)、イベントストリームを促進するメッセージブローカーの役割、そして非同期で高度にデカップリングされた構造を持つEDAの利点について見てきました。
メッセージ・ブローカーは、スケーラブルで信頼性が高く、フォールト・トレラントなApache Kafkaが優れた選択肢となるEDAの設計と有効性にとって重要です。Aiven for Apache Kafkaのようなフルマネージドソリューションでは、Kafkaサービスを必要なサイズで、ご希望のクラウド領域で稼働させながら、EDAの実装に集中することができます。
Aivenのサービスをまだご利用になっていませんか?今すぐhttps://console.aiven.io/signupから無料トライアルにお申し込みください!
Apache Kafka®についてもっと知りたいですか?
必要なものは揃っています!
[Apache Kafkaについて知りたくても聞けなかったことは、すべて無料の電子書籍でご確認ください
また、changelog や blog のRSSフィードや、LinkedIn や Twitter のアカウントをフォローして、製品や機能関連の最新ニュースをチェックしてください。