イベント(Event)とは

イベントドリブンとは何かの前に、プログラミングの文脈におけるイベントについて復習したいと思います。 ここでいうイベントはモジュール(e.g. サービス、プロセス、エンティティ)の持つ状態の変更に対して意味のある名前を付けたものです。 具体例:

  1. ウェブブラウザの「ボタンをクリックした」イベント
  2. 本を販売するサービスの「本を購入した」イベント
  3. 倉庫を表すエンティティの「商品を出庫した」イベント

  イベントは過去の事実のため、過去形で表現することが一般的です。過去の事実ということが大事で、「本を購入した」イベントを作成したあとに間違っていたのでその買った事実を無効にしてほしいといったことはできません。過去におきたことを変えることはできないので「本を返品した」イベントを新しく作成する必要があります。  

イベントドリブン(Event-driven)とは

プログラミングのパラダイムは大小様々なものがありますが、その中でも最も一般的な処理を上から順に記述していく命令型(Imperative)があり、この処理間を「命令」ではなく「イベント」で繋いだ方法はイベントドリブンと呼ばれます。 これをマイクロサービスで言い変えると、サービス間を(例えば)REST APIで繋ぐ方法は命令型で、イベントで繋ぐ方法はイベントドリブンと表現できます。完結に違いを言い表わせば、サービス間の依存の矢印が逆向きになるということです。具体的には、命令型においてサービスAはサービスBを知っていないとBの処理が呼べませんが、イベントドリブンの場合、それとは逆にサービスBがサービスAを知る必要があります。これはサービスAの発行したイベントをサービスBが受け取る必要があるためです。依存の向きが逆になると何が嬉しいのかというと、1つは返答を待たなくて良くなるということです。返答がある前提だとサービスAがサービスBの返答に依存して処理を続ける必要がありますが、返答がないのであればサービスAは自分の責務だけまっとうすれば良く、結果的に処理がシンプルになります。また、サービスBはいつイベントを受け取りたいか(受け取らなくても良い)を自身が決めることができます。その他、後からサービスCがサービスAのイベントを受け取ることもサービスAの変更無しに可能です。 返答がない場合に一連の処理のトリガーであるユーザーはどう返答を受け取れば良いのか気になるかもしれません。これもサービスB同様に最終的にユーザーがイベントを受け取るということが返答の変わりになっています。チャットでのコミュニケーションをイメージしていだくとわかりやすいかもしれません。送信者は受信者がオンラインになったことを確認してからメッセージを送り返信があるまで待機するのが命令型で、送信者はいつでもメッセージを送信し受信者は都合の良いタイミングで返信するのがイベントドリブンです。こうするとリアルタイム性は失われる一方、双方にとって負荷が減り作業時間の短縮になっていることがわかります。ソフトウェアも同様で、イベントドリブンな仕組みではスケールアウトが容易にできることが大きなメリットです。  

  このイベントの中でも、特にサービス間でやり取りされるイベントのことをMicrosoftのドキュメントではインテグレーションイベントと呼んでいるようです。引用元の説明に従えば、同一ドメインを複数のマイクロサービスで分割するアーキテクチャにおいて、そのサービス間でやり取りされるドメインイベントは狭義のインテグレーションイベントにあたります。  

ウェブアプリケーションにおけるアーキテクチャの変遷

イベントドリブンの理解を深めるために、まずはウェブアプリケーションにおけるアーキテクチャの変遷を辿りたいと思います。  

全機能を同一サーバーにまとめた構成

いわゆるモノリスな構成です。
販売、在庫管理、精算等の機能を関数の単位で切り出して同一プロセス内から実行します。
全ての機能をまとめてパッケージングし月に1度本番環境にリリースするようなことをしていました。

別アプリケーションとデータベースを同期して共有する構成

モノリスな構成ではアプリケーションの増改築を繰り返すことで改修の影響範囲が膨大になり、新しいアプリケーションを作るメリットの方が上回るタイミングが早くにやってきます。 そこで、古いアプリケーションを稼働させつつ新しいアプリケーションから古いアプリケーションのデータベースを利用する方法がとられました。 DB変更が両方に影響を与えるため、全アプリケーション間でリリースタイミングを調整し同時にリリースするといったことが必要でした。 

機能を複数アプリケーションで共有できるようサービス単位で切り出した構成

増改築に耐えうるよう機能間の依存を減らし、さらにデータベースをサービスに内包しAPI間でのみデータのやり取りをすることで、決められたルール(API)の中でしかサービスの管理するデータに影響を与えられないようになり、アプリケーション間の依存を大きく減らすことができました。

  あくまでこれは多岐に枝分かれしたアプローチの1つに過ぎませんが、このような経緯を経てクラウドネィティブアプリケーションのアーキテクチャは形作られてきており、今もなお様々な角度から変化を続けています。 一方、様々な軸で良し悪しを比べ現状行き着いた先がこのアーキテクチャでもあるため、ある軸においては大きなデメリットもあります。 その一つが、データの一貫性を保つことが難しくなるということです。そしてこれに対するアプローチとして有効なのがイベントドリブンだと考えています。  

イベントドリブンなマイクロサービス

完結に言えば、複数サービス間で非同期にコミュニケーションする構成です。
サービス間のメッセージのやり取りを送信先を事前に定めずに非同期に行う前提で各サービスを設計することでサービス間をさらに粗結合にしつつも、可用性を上げ障害耐性を高めることが可能になりました。

  さらにデータの一貫性の課題を解消するためには、一連のトランザクション内にあるサービスのいずれかが失敗したら他のサービスを確実にロールバックするためイベントを発行し、これを各サービスが受け取ることでサービスを跨いだデータの一貫性を担保することが可能になります(Sagaパターン)。

Sagaパターンはイベントドリブンアーキテクチャ(EDA)の内、データの一貫性を高めるための1パターンという認識でしたが、Microservice Architecture では「このパターンは非推奨になり、Sagaパターンにおきかわりました。 / This pattern has been deprecated and replaced by the Saga pattern.」という記載があったためEDAとSagaを同列に扱う考え方もあるようです。

  また、エンタープライズアプリケーションにおいては古くから利用されるエンタープライズ・サービス・バス(ESB)がありますが、ESBの主目的は既存のモノリスなアプリケーション資産を連結するための腐敗防止層という意味合いが強く、非同期なイベントハンドリングの仕組みを実現するには高機能な印象があります。そのため、メッセージドリブン/イベントソーシング/DDD/そしてマイクロサービスの文脈を経て行き着くアーキテクチャの構成要素の1つであるインテグレーションイベントやSagaパターンは、ESBを利用すると実現できはすれどもともとの背景思想は異なるため、ESBはイベントドリブンのためのいち手段という理解です。

終わりに

クラウドネイティブアプリケーションにおいて、コスト削減や可用性向上のための適切なインフラレイヤー(実行環境)の選択が重要になり、1つのアプリケーションは複数の実行環境にデプロイされたサービスが組み合わさり構成されるようになりました。これにより実行環境を跨いだ処理間の連携をどう設計するかの重要性が増してきています。そこで今回解説したイベントドリブンな設計はデータの一貫性担保、可用性向上において有効な手段であることが示せたと思います。 次回以降ではより具体的な設計、例えばリプレイのためのイベント設計やDDDやCQRSとの相性の良さについて解説していこうと考えております。  


Written by Yuki Sanada

デジタルサービス開発のポイント&事例の紹介資料をご確認ください! ウェブアプリケーションをお客様向けに提供し、顧客体験を向上することがますます求められています。TC3では、顧顧客向けのサービス開発をクラウドネイティブな考え方/技術、アジャイル開発の手法を活用してご支援しています。顧客向けのデジタルサービスを開発する上でのポイントとあわせて、事例をご紹介している資料は以下からダウンロードいただけます。

デジタル顧客接点トータルサービス CTA

デジタル顧客接点トータルサービス』のご紹介資料を含めたウェビナー資料(事例も掲載しています)以下のフォームからご確認いただけます。(フォームが表示されない場合には、こちらからご確認ください) 資料ダウンロードは以下のフォームにご記入ください。