All Articles

event driven architecture

Practical Event-Driven Microservices Architecture- Building Sustainable and Highly Scalable Event-Driven Microservices を読んでみている。

どんな人が書いたの?

アパレルEC、Farfetch で働く 2人のエンジニア。 Hugo さんは 高度に分散されたイベント駆動型のマイクロサービス・アーキテクチャに10年近く携わってきた経験を持つ。 数百万のアクティブユーザーにサービスを提供し、数百のマイクロサービスが毎秒数百の変更を処理するイベントドリブンアーキテクチャを支えている。

気になったことベースメモ

従来のアプリケーションよりも数桁大きいデータを扱う場合、グローバルに、さまざまなスループットで一貫して数秒単位で情報を提供し、ほとんどの障害モードに耐性を持つことでより高い可用性を達成することは、従来のアーキテクチャが解決するために作られたものではない、根本的に異なる課題である。

近年、イベント・ドリブン・アーキテクチャは、ソフトウェア・アーキテクチャ設計の強力なアプローチとして、また、使用量の増加、分散データ、スケールでのデータ共有など、アプリケーションが直面する困難な課題への回答として登場した。イベント・ドリブン・アーキテクチャの特筆すべき特徴は、イベント・ストリームにフォーカスしていることである。単にアプリケーションをイベントに反応させるだけでなく、イベント・ストリームが全社的なデータ共有の中心となる。データはもはやデータベース上にのみ置かれ、同期インターフェイスを通じてのみアクセスできるのではなく、イベント・ストリームで共有され、現在および将来のすべての消費者が容易に利用できるようになる。 その代わり、データはイベント・ストリームで共有され、現在および将来のすべての消費者がすぐに利用できるようになります。

DB からではなく、ストリームからクライアントはデータを取ることになると。

本書は、イベントドリブンアーキテクチャをいつ、どこで使うべきか、そしてその利点を十分に享受するにはどうすればよいかを明らかにするものである。 その利点を十分に享受する方法を提案する。イベントドリブンアーキテクチャの最も難しい特徴に対処するためのパターンとアプローチ、そしてイベントドリブンアーキテクチャを段階的かつ持続的に採用する方法を提案する。

  • モノリスがどのようにビジネスの成長を妨げるか、またその主な限界について
  • マイクロサービスとその優位性、イベントドリブンアーキテクチャとの関連性を理解する。
  • イベント駆動型マイクロサービスの採用の可能性を認識し、イベント駆動型アーキテクチャがどのように機能するか
  • イベント駆動型アーキテクチャに移行するビジネスの必要性をどのように特定するか
  • マイクロサービスのイベント駆動型アーキテクチャを採用する際の課題を知る

結局のところ、複雑なビジネスは、最終的に私たちが開発する技術的ソリューションにその複雑さを反映する。私たちの義務であり使命は、ビジネスの成長、スケール、ベロシティ、新機能のいずれかを可能にする方法で、その複雑性をモデル化することだ。イベント・ドリブン・アーキテクチャーは、まさにそれを実現する方法を提案する。

モノリスのどんな部分が問題になるか

  • 境界線がないことで、ドメインロジックが絡みあい、複雑になってしまう。何が起きるかというと、ある変更による影響範囲が読めなくなってしまう。または、予期せぬ不具合を起こしてしまう。

対してモジュラモノリスは、境界が整備されているので一見安定するように見える。 落とし穴は

  • 簡単にモジュール制約を破ることが可能。(設計次第で防げる)
  • 1つのモジュールを変更したとしてもすべてのモジュールのデプロイが必要になる

Go の場合は internal パッケージで簡単に防ぐことができる。 JS でやる場合は Nx とか使うのかな。Nx の使い方をちゃんと学んで構成設計しないといけない。

単一のコードベースがあれば、エンド・ツー・エンドのフローを素早く検査できる。すべての機能が1つのリポジトリにあるので、欲しい機能を簡単に見つけることができる。また、フローの依存関係を見ることができるので、新しい開発の影響を見るのも簡単だ。イベント・ドリブン・アーキテクチャーでは、ビジネス・フローが読みにくくなることがある。 イベント駆動型アーキテクチャでは、複数のサービス間で非同期的な相互作用が発生するため、ビジネスフローが読みづらくなる可能性がある。ビジネスプロセスを理解するには、各サービス間のイベントの流れを理解する必要がある。新しい機能を追加するときには、起こりうる影響を考慮したり、その機能にとって正しい開発かどうかを理解したりするために、全体像を把握することが常に重要になります。モノリスでは、それらが全体的な流れの中でどのようにフィットしているかを理解することは(時には手間がかかるが)可能である。

これはその通りだと思う、キューで連結された通信は処理が追いづらくてしんどい。ワークフローになっていてほしい。

イベントドリブンアーキテクチャでは、イベントのコンシューマが新しいものに適応できるように、一時的に2つのバージョンのイベントをサポートしたり、2つのバージョンのAPIをサポートしたりする必要があるだろう。これらの変更は、複数のサービスに影響を与える可能性があるため、複雑である。新しいイベントへの移行を調整するために、異なるチーム間の調整が必要である。2つのイベントの発行と消費の開発、そして古いイベントの削除のために、かなりの開発オーバーヘッドが発生する。モノリスでは、これは簡単なことで、1つのアプリケーションを変更してリリースするだけです。

イベント駆動でブレーキングチェンジにどう対応するのかなと思ってたけど、やはり複数イベントを発行して購読しあうしかないのか。

モノリスでは、環境全体をローカルで実行することが可能だ(ただし、ビルドするだけで数分かかり、ローカルで起動するだけでさらに数分かかるアプリケーションを見た)。多くの場合、1つのアプリケーションを実行することで、機能を追加し、検証することができる。しかし、イベント・ドリブン・アーキテクチャでは、ワークフロー内の複数のサービスのうちの1つに機能を追加することになる。そのため、ワークフロー全体をローカルで実行するのは難しい。

結合試験が大事になってくる?そこに投資できるか。モノリスであれば結合試験スクリプトも作りやすい。チームが少人数の場合は、一人が複数サービス変更するのは不毛なのでスケールメリットが感じられるまではモノリスかな。あるいは非機能要件的な何かがある場合。

イベントドリブンアーキテクチャでは、エンドツーエンドのテストは行わず(あるいは、その量を大幅に減らし)、品質を保証するための他のプロセスを持つという、シングルピースのアプローチから移行しなければなりません

違うらしい。設計レベルやテスト方法がそもそも異なる。

モノリスの監視は、1つのアプリケーションだけなので簡単です。監視するマシンの数が減り 監視するマシンの数が減り、ログを取得するのも簡単です。スコープが1つのアプリケーションに絞られるため、問題のトラブルシューティングも簡単になります。イベント駆動型アーキテクチャでは、数十から数百のマイクロサービスのインスタンスが複数存在する。このため、インシデントのモニタリングとピンポイントの特定には、まったく異なる戦略が必要になる。それらすべてのマイクロサービスのシグナルとメトリクスを管理するための既存のインフラが必要になる。また、インシデントを理解することは、意図的なアプローチがなければ、短編小説にふさわしい探偵の旅になりかねない。一方、モノリスは、情報がはるかに局所化されているため、はるかに簡単です。

監視への投資も必要。内部のロギングも統制とれてないとつらい。RequestID を取り回す仕組み。これはマイクロサービスも同じ。

デプロイも分ける必要がある。

イベント・ドリブン・アーキテクチャは、一から水平スケーリングのために構築されており、スケーリングがはるかに容易です。

従来のモノリスをALBの後段に置いてスケールさせるよりも。これは、DB がスケールしにくい。

モノリスでは、強力な一貫性保証を持つリレーショナルOLTP(オンライントランザクション処理)データベースを使用することが多い。モノリシック・アプリケーション上のこれらのタイプのデータベースは、通常ACID(原子性、一貫性、分離、耐久性)保証を享受します。 例えば、変更はどこでも同時に発生します。イベント・ドリブン・アーキテクチャでは、イベントの非同期性のため、一貫性はしばしば偶発的一貫性であり、その対処は困難です

一貫性の問題はそう。大きなトレードオフになる。複数サービスで整合性必要になったら地獄というか実装上ヘビーなものが生まれうる。

モノリスの主な問題は、十分な時間があれば、耐えられないほど複雑になり、結合してしまうことだ。すべての機能が単一のアプリケーションの中にあるので、各ドメインの境界を妥協するのは比較的簡単だ。時間が経つにつれて、それぞれの境界は薄れ、絡み合って読みづらくなる。例えば、サブスクリプションのロジックを変更するとログインに影響する。

単一のモノリシック・アプリケーションのリリース・サイクルは、通常マイクロサービスよりも大きい。たとえ企業が継続的デリバリーを採用したとしても、リリースのたびにサイクルは本質的に大きくなります;どんなに小さな変更であっても、アプリケーション全体を検証してデプロイしなければなりません。どんなに小さな変更であっても、アプリケーション全体を検証してデプロイしなければならない。アプリケーション全体を一度に検証するには、実行にかなりの時間を要する巨大なテスト・スイートが必要になる(手作業による検証がないと仮定すると、多くの場合そうなる)。小さな変更は、デプロイメントをよりコントロールしやすくし、素早いフィードバックを可能にする。 一般的に、モノリスに依存しているビジネスでは、常にアプリケーション全体をデプロイしているため、リスクのためにそれほど頻繁には(例えば毎日)デプロイしません。それほど頻繁にデプロイしないことで、機能が蓄積され、継続的デリバリーの考え方を持つことが難しくなる。それだけでも、モノリスから離れるための一般的な議論だ。

ただし、継続的デリバリーできる単位で境界線を定められている場合に限る。やはり機能の蓄積は悪。 デプロイをコントロールできるようになるメリットはそれだけ大きい。

モノリスはモノリシックデータベースを育てます。データ量が非常に多くなり始めると、特に多くの結合を必要とするクエリで問題が発生する。垂直スケーリング(メモリやCPUなどリソースの数を増やすこと)は、データベースとアプリケーションの両方にとって常に選択肢の一つだが、すぐにコストがかさんでしまう。ビジネスが成長し、各地に低レイテンシーを提供する地理的分散が必要な段階になった場合、モノリシックなデータベースではそれを実現する能力が制限される可能性がある。

グローバルな観点も出てきた。これは確かに。でも今どきはどうなんだろ。Google は Spanner で何とかなってるし。

ほとんどの場合、スケーリングが必要なのはモジュールの一部だけです。しかし、すべてのモジュールは結合されているため、唯一の選択肢はアプリケーション全体をスケールすることだ。マイクロサービス・アプローチを使用することで、スケーリングが必要なアーキテクチャの部分のみをスケーリングし、残りの部分は最小限のリソースに残すことができ、コストとリソースを最適化することができる。

これは経験的にもそう、自然にそうなることもあるし、予期することもできる。

技術的負債や不要になった機能性を除去するのは難しい。 技術的負債や不要になった機能性を削除することは、境界間の結合のために困難である。モジュール化されたモノリス(Shopifyは税務エンジンでこれを実現した4)であればこれを実現できるが、ほとんどの場合、機能を削除したり置き換えたりするには、アプリケーション全体に触れることになり、予期せぬ結果を招く可能性がある。どのようなサービスでも時代遅れのテクノロジー・スタックを持つ可能性があるが、イベント駆動型サービスは高度に切り離されているため、既存のサービスを新しいテクノロジーで実装することは非常に単純化される。

技術の交換性というか、ライブラリ依存の切り離しがやりやすい観点は考えたことなかった。ただここも会社の方針がなるべく同じライブラリ使おうならメリット薄いのかも?

どのフェーズでモノリスでの開発が苦しくなりそう?

どのドメインを新しいアーキテクチャに移行させるかを選択するのは、必ずしも簡単なことではない。リスクとはビジネスドメインの重要性、価値とはそのドメインを移行することで得られるかもしれない利益、実行可能性とはそのドメインを移行することがどれだけ現実的で実行可能であるかということである。

イベント駆動型マイクロサービスとは、イベントに反応して作業を行う、シンプルで特定の目的を持ったサービスのことです。イベント・ドリブン・アーキテクチャーでは、複数のサービスが相互に作用しあって、より高度なプロセスを達成します。通常、相互作用は異なるサービス間の一連のイベントによって構成される。 イベント駆動型アーキテクチャは、これらの疎結合サービスを介したメッセージの流れを利用してビジネスプロセスを達成する。各サービスは所定のドメインまたは境界コンテキストに属し、そのドメイン内で特定の役割と限定された責任を持つ。各ドメインは、そのドメイン内の関連データを処理し、その変更を他のドメインに伝達する責任を持つ。

サービスを特定のドメインや、境界コンテキストに置くのが絶対に大事。なるべくサービス同士で依存を作りたくない。

SOAは、モノリスのような単一のアプリケーションの同期フローではなく、複雑なワークフローを達成するために振り付けを行うサービスで構成される。また、サービス間の通信にはメッセージングを使用する。一見すると、確かにイベントドリブンアーキテクチャと似ているように聞こえるが、両者は根本的に異なる。 SOAは通常、ネットワークやサービスバスのような分離された媒体を通じて通信する再利用可能なコンポーネントを使用してビジネス機能を構築しようとするものである。

アプリケーションサービスの背後にある考え方は、機能を再利用可能にすることであり、これは、機能の共有が制限される(避けられることさえある)マイクロ サービスやイベント駆動型とは対照的に、この種のアーキテクチャ(SOA)における設計上の中心的な関心事である。SOAが抽象的で再利用可能な機能に重点を置いているの に対し、マイクロサービスやイベント駆動型アーキテクチャは、ドメインを中心に コンポーネントを編成することに重点を置いている。SOAではサービスバスがますます大きくなる傾向がある。ビジネスロジ ックは、サービスの代わりにバスに追加される傾向がある。バスはまた、オーケス トレーション以外にもいくつかの責任を担っている。バスは通常、各サービスとの 通信をルーティングし、知るコンポーネントであり、多くの場合、リクエストを適応させ、変換するロジックを持つ。エンタープライズ・サービス・バスは、アーキ テクチャ全体が分散しているにもかかわらず、それ自体が成長してモノリスになる 傾向があり、多くの場合、両方の悪い面を持っている。

マイクロサービス・イベント駆動型アーキテク チャは、マイクロサービス・アーキテクチャの原則の多くを共有している。しかし 、サービス間の相互作用はイベントの使い方に焦点を当てています。

マイクロサービスはお互いを呼び合うことでビジネスロジックが行われるのに対し、イベント駆動はイベントに対してサービスが反応する形でビジネスロジックが行われる。 なので、基本的にはメッセージキューに対して、サービスが反応する形になる。 これのメリットは、拡張容易性と疎結合にある。何か新しいサービスがイベントに参加するときにイベントストリームからイベントを取得するだけでよい。ビジネスプロセスに参加できる。イベント発行者は参加者が増えたからと言って処理を変更する必要がない。

イベント駆動型のマイクロサービス・アーキテ クチャでは、この種のフォールトは自然にそのコンポーネントにバインドされるた め、1つが故障しても他のコンポーネントは稼働し続ける。 イベントドリブンは、メッセージキューによって提供されるデカップリングに よって、同期マイクロサービスアプリケーションよりも高い耐障害性を達成する 。

イベント・ドリブン・アーキテクチャは、イベントを通じてデータを共有することができる。この共有は、現在起こっている情報に限定され るのではなく、現在までのイベントの全履歴を提供する。

これってdynamoDBとかでいうと全履歴残しているってことなんだろうか。フェッチコストが高くなりそうだけど、ページングしていくのが基本なのかな。

イベント・ドリブン・アーキテクチャを設計するための基本的なステップは、サ ービスの規模と範囲を正しく把握することである。これには公式がなく、主観的に なりやすい。 最も有効な戦略は、DDD(ドメイン駆動設計)に従い、サービス間の境界コンテキストを正しくすることである。

ほどの場合、テクノロジーを本当に学び、その限界の範囲を理解するためには、本番で大規模に実行する必要がある。イベント・ドリブン・アーキテクチャの複雑さ、分散特性、非同期性は、複雑な課題への道を開く。それらを管理するためには、意図的な戦略が必要である。本書はこれらの課題にアプローチし対処するための戦略を提案する。

イベント・ドリブンアーキテクチャを採用したときに起こりうる課題

  • 変更がまだ伝播している間に、異なるシステム部分が古いデータを顧客や他の顧客に返すかもしれない。古くなったデータどう扱うの
  • 最終的な一貫性を扱うための解決策が必要
  • 最終的な一貫性とサービスの非同期性は、UIデザインに異なるアプローチを必 要とする
  • イベントの順番が入れ替わると、サービスが最新のイベントの後に古いイベントを 処理することになり、一貫性が失われる可能性がある。順番を保証するブローカーもあるが、ほとんどはそうではない
  • イベントスキーマとそのサイズがしばしば活発な議論のトピックとなる ため、コントラクトはシステム設計にとって極めて重要になる。イベントをどのよ うに設計するかによって、どちらのアプローチにもトレードオフがある
  • イベント・ドリブン・アーキテクチャーでは、何かを 修正するということは、多くの場合、逆の操作のコマンドを送信することを意味する。通常は、このような操作を可能にするために、一からカスタムツールを作成する必要がある
  • サービス間のデカップリングは並行作業を促進するが、時には複数のチーム間の複雑な依存関係が発生する
  • 1つのコンポー ネントをデプロイするたびにエンド・ツー・エンドのフローの品質を保証すると いう課題が生じる

一旦ここまで