ブログ | NGINX

マイクロサービス向けイベント駆動型データ管理

NGINX-F5 水平黒タイプ RGB の一部
クリス・リチャードソン サムネイル
クリス・リチャードソン
2015 年 12 月 4 日公開

編集者– この 7 部構成の記事シリーズはこれで完了です。

  1. マイクロサービス入門
  2. マイクロサービスの構築: APIゲートウェイの使用
  3. マイクロサービスの構築: マイクロサービス アーキテクチャにおけるプロセス間通信
  4. マイクロサービス アーキテクチャにおけるサービス検出
  5. マイクロサービス向けイベント駆動型データ管理(この記事)
  6. マイクロサービス導入戦略の選択
  7. モノリスをマイクロサービスにリファクタリングする

また、記事の完全なセットと、NGINX Plus を使用したマイクロサービスの実装に関する情報を電子書籍「マイクロサービス」としてダウンロードすることもできます。 設計から展開まで。 また、マイクロサービス リファレンス アーキテクチャマイクロサービス ソリューション ページに関するシリーズもご覧ください。

これは、マイクロサービスを使用したアプリケーションの構築に関するシリーズの 5 番目の記事です。 最初の記事では、マイクロサービス アーキテクチャ パターンを紹介し、マイクロサービスを使用する利点と欠点について説明します。 シリーズの2 番目と3 番目の記事では、マイクロサービス アーキテクチャ内の通信のさまざまな側面について説明します。 4 番目の記事では、サービス検出という密接に関連する問題について説明します。 この記事では、話題を変えて、マイクロサービス アーキテクチャで発生する分散データ管理の問題について見ていきます。

マイクロサービスと分散データ管理の問題

モノリシック アプリケーションには通常、単一のリレーショナル データベースがあります。 リレーショナル データベースを使用する主な利点は、アプリケーションでACID トランザクションを使用できることです。これにより、次のような重要な保証が得られます。

  • アトミック性 – 変更はアトミックに行われる
  • 一貫性 – データベースの状態は常に一貫しています
  • 分離性 – トランザクションは同時に実行されているにもかかわらず、順番に実行されているように見える
  • 耐久性 – トランザクションがコミットされると元に戻すことはできません

その結果、アプリケーションはトランザクションを開始し、複数の行を変更 (挿入、更新、削除) し、トランザクションをコミットするだけで済みます。

リレーショナル データベースを使用するもう 1 つの大きな利点は、機能豊富で宣言型の標準化されたクエリ言語である SQL が提供されることです。 複数のテーブルのデータを組み合わせるクエリを簡単に作成できます。 次に、RDBMS クエリ プランナーはクエリを実行するための最適な方法を決定します。 データベースへのアクセス方法などの低レベルの詳細について心配する必要はありません。 また、アプリケーションのデータはすべて 1 つのデータベースに保存されるため、クエリも簡単に実行できます。

残念ながら、マイクロサービス アーキテクチャに移行すると、データ アクセスははるかに複雑になります。 これは、各マイクロサービスが所有するデータはそのマイクロサービス専用であり、その API 経由でのみアクセスできるためです。データをカプセル化することで、マイクロサービスが疎結合され、互いに独立して進化できるようになります。 複数のサービスが同じデータにアクセスする場合、スキーマの更新には、すべてのサービスに対する時間のかかる調整された更新が必要になります。

さらに悪いことに、異なるマイクロサービスでは異なる種類のデータベースが使用されることがよくあります。 現代のアプリケーションはさまざまな種類のデータを保存および処理するため、リレーショナル データベースが常に最適な選択であるとは限りません。 一部のユースケースでは、特定の NoSQL データベースの方がデータ モデルが便利で、パフォーマンスとスケーラビリティが大幅に向上する場合があります。 たとえば、テキストを保存してクエリを実行するサービスでは、Elasticsearch などのテキスト検索エンジンを使用するのが理にかなっています。 同様に、ソーシャル グラフ データを保存するサービスでは、Neo4j などのグラフ データベースを使用する必要があるでしょう。 その結果、マイクロサービス ベースのアプリケーションでは、SQL データベースと NoSQL データベースを組み合わせて使用することが多く、いわゆるポリグロット永続化アプローチが使用されます。

データ ストレージ用のパーティション化された多言語永続アーキテクチャには、疎結合サービスやパフォーマンスとスケーラビリティの向上など、多くの利点があります。 ただし、分散データ管理の課題がいくつか発生します。

最初の課題は、複数のサービス間で一貫性を維持するビジネス トランザクションをどのように実装するかです。 これがなぜ問題なのかを理解するために、オンライン B2B ストアの例を見てみましょう。 カスタマー サービスは、顧客の信用限度額を含む顧客に関する情報を管理します。 注文サービスは注文を管理し、新しい注文が顧客の信用限度額を超えていないことを確認する必要があります。 このアプリケーションのモノリシック バージョンでは、注文サービスは ACID トランザクションを使用するだけで、利用可能なクレジットを確認し、注文を作成できます。

対照的に、マイクロサービス アーキテクチャでは、次の図に示すように、ORDER テーブルと CUSTOMER テーブルはそれぞれのサービスに対してプライベートになります。

マイクロサービスアーキテクチャの各サービスはプライベートデータベーステーブルを維持します

注文サービスは CUSTOMER テーブルに直接アクセスできません。 カスタマーサービスが提供する API のみを使用できます。 注文サービスは、2 フェーズ コミット (2PC) とも呼ばれる分散トランザクションを使用する可能性があります。 ただし、2PC は通常、最新のアプリケーションでは実行可能なオプションではありません。 CAP 定理では、可用性と ACID スタイルの一貫性のどちらかを選択する必要があり、通常は可用性の方が優れた選択肢となります。 さらに、ほとんどの NoSQL データベースなど、多くの最新テクノロジーは 2PC をサポートしていません。サービスとデータベース間でデータの一貫性を維持することが重要であるため、別のソリューションが必要です。

2 番目の課題は、複数のサービスからデータを取得するクエリをどのように実装するかです。 たとえば、アプリケーションで顧客とその最近の注文を表示する必要があるとします。 注文サービスが顧客の注文を取得するための API を提供している場合は、アプリケーション側の結合を使用してこのデータを取得できます。 アプリケーションは、顧客サービスから顧客を取得し、注文サービスから顧客の注文を取得します。 ただし、注文サービスが主キーによる注文の検索のみをサポートしているとします (おそらく、主キー ベースの取得のみをサポートする NoSQL データベースを使用します)。 このような状況では、必要なデータを取得する明確な方法はありません。

イベント駆動型アーキテクチャ

多くのアプリケーションでは、イベント駆動型アーキテクチャを使用することが解決策となります。 このアーキテクチャでは、マイクロサービスは、ビジネス エンティティを更新するときなど、何か注目すべきことが発生したときにイベントを発行します。 他のマイクロサービスはそれらのイベントをサブスクライブします。 マイクロサービスがイベントを受信すると、独自のビジネス エンティティを更新できるため、さらに多くのイベントが公開される可能性があります。

イベントを使用すると、複数のサービスにまたがるビジネス トランザクションを実装できます。 トランザクションは一連のステップで構成されます。 各ステップは、ビジネス エンティティを更新し、次のステップをトリガーするイベントを公開するマイクロサービスで構成されます。 次の一連の図は、注文の作成時に利用可能なクレジットを確認するためにイベント駆動型のアプローチを使用する方法を示しています。 マイクロサービスはメッセージ ブローカーを介してイベントを交換します。

  1. 注文サービスは、ステータスが NEW の注文を作成し、注文作成イベントを発行します。

    マイクロサービスアーキテクチャにおける信用調査のステップ1では、注文サービスが「注文作成」イベントを発行します。

  2. カスタマー サービスは、注文作成イベントを消費し、注文のクレジットを予約し、クレジット予約イベントを発行します。

    マイクロサービスアーキテクチャでは、クレジットチェックの2番目のステップは、カスタマーサービスが「クレジット予約」イベントを生成することです。

  3. 注文サービスは、Credit Reserved イベントを消費し、注文のステータスを OPEN に変更します。

    マイクロサービスアーキテクチャでは、信用調査の3番目のステップは、注文サービスが注文ステータスを「オープン」に設定することです。

より複雑なシナリオでは、顧客の信用を確認すると同時に在庫を予約するなどの追加の手順が必要になる場合があります。

(a) 各サービスがデータベースを自動的に更新し、イベントを発行し (これについては後で詳しく説明します)、(b) メッセージ ブローカーがイベントが少なくとも 1 回は配信されることを保証する場合、複数のサービスにまたがるビジネス トランザクションを実装できます。 これらは ACID トランザクションではないことに注意することが重要です。 最終的な一貫性など、はるかに弱い保証を提供します。 このトランザクション モデルはBASE モデルと呼ばれています。

また、イベントを使用して、複数のマイクロサービスが所有するデータを事前結合するマテリアライズド ビューを維持することもできます。 ビューを維持するサービスは、関連するイベントをサブスクライブし、ビューを更新します。 たとえば、顧客注文ビューを管理する顧客注文ビュー アップデータ サービスは、顧客サービスと注文サービスによって公開されたイベントをサブスクライブします。

マイクロサービスアーキテクチャでは、サービスはアクションのトリガーとして他のサービスによって発行されたイベント通知をサブスクライブできます。

顧客注文ビュー アップデータ サービスは、顧客イベントまたは注文イベントを受信すると、顧客注文ビュー データストアを更新します。 MongoDB などのドキュメント データベースを使用して顧客注文ビューを実装し、顧客ごとに 1 つのドキュメントを保存できます。 顧客注文ビュー クエリ サービスは、顧客注文ビュー データストアをクエリして、顧客および最近の注文のリクエストを処理します。

イベント駆動型アーキテクチャには、いくつかの利点と欠点があります。 複数のサービスにまたがるトランザクションの実装を可能にし、最終的な一貫性を実現します。 もう 1 つの利点は、アプリケーションがマテリアライズド ビューを維持できるようになることです。 1 つの欠点は、ACID トランザクションを使用する場合よりもプログラミング モデルが複雑になることです。 多くの場合、アプリケーション レベルの障害から回復するために補正トランザクションを実装する必要があります。たとえば、クレジット チェックが失敗した場合は注文をキャンセルする必要があります。 また、アプリケーションは矛盾したデータを処理する必要があります。 これは、実行中のトランザクションによって行われた変更が可視となるためです。 アプリケーションは、まだ更新されていないマテリアライズド ビューから読み取る場合にも不整合を検出する可能性があります。 もう 1 つの欠点は、サブスクライバーが重複したイベントを検出して無視する必要があることです。

原子性の実現

イベント駆動型アーキテクチャでは、データベースをアトミックに更新し、イベントを発行するという問題もあります。 たとえば、注文サービスは ORDER テーブルに行を挿入し、注文作成イベントを発行する必要があります。 これら 2 つの操作はアトミックに実行されることが重要です。 データベースを更新した後、イベントを公開する前にサービスがクラッシュすると、システムの整合性が失われます。 アトミック性を保証する標準的な方法は、データベースとメッセージ ブローカーを含む分散トランザクションを使用することです。 しかし、CAP 定理などの上記の理由により、これはまさに私たちが望んでいないことです。

ローカルトランザクションを使用したイベントの公開

アトミック性を実現する 1 つの方法は、アプリケーションがローカル トランザクションのみを含む複数ステップのプロセスを使用してイベントを公開することです。 秘訣は、ビジネス エンティティの状態を格納するデータベース内に、メッセージ キューとして機能する EVENT テーブルを用意することです。 アプリケーションは (ローカル) データベース トランザクションを開始し、ビジネス エンティティの状態を更新し、EVENT テーブルにイベントを挿入して、トランザクションをコミットします。 別のアプリケーション スレッドまたはプロセスが EVENT テーブルを照会し、イベントをメッセージ ブローカーに公開し、ローカル トランザクションを使用してイベントを公開済みとしてマークします。 次の図は設計を示しています。

マイクロサービスアーキテクチャでは、ローカルトランザクションのみを使用してイベントを公開することでアトミック性を実現します。

注文サービスは、ORDER テーブルに行を挿入し、EVENT テーブルに Order Created イベントを挿入します。 イベント パブリッシャー スレッドまたはプロセスは、EVENT テーブルで未公開のイベントを照会し、イベントを公開してから、EVENT テーブルを更新してイベントを公開済みとしてマークします。

このアプローチにはいくつかの利点と欠点があります。 1 つの利点は、2PC に依存せずに更新ごとにイベントが公開されることが保証されることです。また、アプリケーションはビジネス レベルのイベントを公開するため、イベントを推測する必要がなくなります。 このアプローチの欠点の 1 つは、開発者がイベントの公開を忘れないようにする必要があるため、エラーが発生しやすくなる可能性があることです。 このアプローチの制限は、トランザクションとクエリの機能が制限されているため、一部の NoSQL データベースを使用する場合に実装が難しいことです。

このアプローチでは、アプリケーションがローカル トランザクションを使用して状態を更新し、イベントを公開することで、2PC の必要性がなくなります。 次に、アプリケーションが状態を更新するだけでアトミック性を実現するアプローチを見てみましょう。

データベーストランザクションログのマイニング

2PC を使用せずにアトミック性を実現するもう 1 つの方法は、データベースのトランザクション ログまたはコミット ログをマイニングするスレッドまたはプロセスによってイベントを公開することです。 アプリケーションがデータベースを更新すると、変更がデータベースのトランザクション ログに記録されます。 トランザクション ログ マイナー スレッドまたはプロセスは、トランザクション ログを読み取り、メッセージ ブローカーにイベントを公開します。 次の図は設計を示しています。

マイクロサービスアーキテクチャでは、トランザクションログからイベントをマイニングすることでアトミック性を実現します。

このアプローチの一例としては、オープンソースのLinkedIn Databusプロジェクトがあります。 Databus は Oracle トランザクション ログをマイニングし、変更に対応するイベントを公開します。 LinkedIn は、Databus を使用して、さまざまな派生データ ストアをレコード システムと一貫性のある状態に保ちます。

もう 1 つの例は、マネージド NoSQL データベースであるAWS DynamoDB のストリーム メカニズムです。 DynamoDB ストリームには、過去 24 時間以内に DynamoDB テーブル内の項目に対して行われた変更 (作成、更新、削除操作) の時間順のシーケンスが含まれます。 アプリケーションはストリームからこれらの変更を読み取り、たとえばイベントとして公開することができます。

トランザクション ログ マイニングにはさまざまな利点と欠点があります。 1 つの利点は、2PC を使用せずに更新ごとにイベントが公開されることを保証することです。トランザクション ログ マイニングでは、イベントの公開をアプリケーションのビジネス ロジックから分離することで、アプリケーションを簡素化することもできます。 大きな欠点は、トランザクション ログの形式が各データベースに固有のものであり、データベースのバージョン間で変更される可能性があることです。 また、トランザクション ログに記録された低レベルの更新から高レベルのビジネス イベントをリバース エンジニアリングすることは困難な場合があります。

トランザクション ログ マイニングでは、アプリケーションがデータベースを更新するという 1 つの処理を実行するため、2PC が不要になります。 ここで、更新を排除し、イベントのみに依存する別のアプローチを見てみましょう。

イベントソーシングの使用

イベント ソーシングは、ビジネス エンティティを永続化するための根本的に異なるイベント中心のアプローチを使用することで、2PC なしでアトミック性を実現します。 アプリケーションは、エンティティの現在の状態を保存するのではなく、状態を変更する一連のイベントを保存します。 アプリケーションは、イベントを再生することでエンティティの現在の状態を再構築します。 ビジネス エンティティの状態が変化するたびに、新しいイベントがイベント リストに追加されます。 イベントの保存は単一の操作であるため、本質的にアトミックです。

イベント ソーシングがどのように機能するかを確認するには、Order エンティティを例として考えます。 従来のアプローチでは、各注文は ORDER テーブルの行と、たとえば ORDER_LINE_ITEM テーブルの行にマップされます。 ただし、イベント ソーシングを使用する場合、注文サービスは注文を状態変更イベントの形式で保存します。 作成、承認、発送、キャンセル。 各イベントには、オーダーの状態を再構築するのに十分なデータが含まれています。

マイクロサービスアーキテクチャでは、イベントソーシングでアトミック性を実現します。

イベントは、イベントのデータベースであるイベント ストアに保存されます。 ストアには、エンティティのイベントを追加および取得するための API があります。 イベント ストアは、前述したアーキテクチャのメッセージ ブローカーのようにも動作します。 サービスがイベントをサブスクライブできるようにする API を提供します。 イベント ストアは、すべてのイベントを関心のあるすべてのサブスクライバーに配信します。 イベント ストアは、イベント駆動型マイクロサービス アーキテクチャのバックボーンです。

イベントソーシングにはいくつかの利点があります。 これは、イベント駆動型アーキテクチャの実装における主要な問題の 1 つを解決し、状態が変化するたびにイベントを確実に公開することを可能にします。 その結果、マイクロサービス アーキテクチャにおけるデータの一貫性の問題が解決されます。 また、ドメイン オブジェクトではなくイベントを永続化するため、オブジェクト リレーショナルのインピーダンス不一致の問題をほぼ回避できます。 イベント ソーシングは、ビジネス エンティティに加えられた変更の 100% 信頼性の高い監査ログも提供し、任意の時点でのエンティティの状態を判断する一時的なクエリを実装することも可能にします。 イベント ソーシングのもう 1 つの大きな利点は、ビジネス ロジックが、イベントを交換する疎結合のビジネス エンティティで構成されていることです。 これにより、モノリシック アプリケーションからマイクロサービス アーキテクチャへの移行がはるかに簡単になります。

イベントソーシングにもいくつかの欠点があります。 これは、異なる、馴染みのないプログラミング スタイルであるため、学習曲線があります。 イベント ストアは、主キーによるビジネス エンティティの検索のみを直接サポートします。 クエリを実装するには、コマンド クエリ責任分離(CQRS) を使用する必要があります。 その結果、アプリケーションは最終的に一貫性のあるデータを処理する必要があります。

まとめ

マイクロサービス アーキテクチャでは、各マイクロサービスに独自のプライベート データストアがあります。 異なるマイクロサービスでは、異なる SQL データベースと NoSQL データベースが使用される場合があります。 このデータベース アーキテクチャには大きな利点がありますが、分散データ管理の課題もいくつか生じます。 最初の課題は、複数のサービス間で一貫性を維持するビジネス トランザクションをどのように実装するかです。 2 番目の課題は、複数のサービスからデータを取得するクエリをどのように実装するかです。

多くのアプリケーションでは、イベント駆動型アーキテクチャを使用するのが解決策となります。 イベント駆動型アーキテクチャを実装する際の課題の 1 つは、状態をアトミックに更新し、イベントを公開する方法です。 これを実現するには、データベースをメッセージ キューとして使用すること、トランザクション ログ マイニング、イベント ソースなど、いくつかの方法があります。

今後のブログ投稿では、マイクロサービスの他の側面についても引き続き詳しく説明します。

編集者– この 7 部構成の記事シリーズはこれで完了です。

  1. マイクロサービス入門
  2. マイクロサービスの構築: APIゲートウェイの使用
  3. マイクロサービスの構築: マイクロサービス アーキテクチャにおけるプロセス間通信
  4. マイクロサービス アーキテクチャにおけるサービス検出
  5. マイクロサービス向けイベント駆動型データ管理(この記事)
  6. マイクロサービス導入戦略の選択
  7. モノリスをマイクロサービスにリファクタリングする

また、記事の完全なセットと、NGINX Plus を使用したマイクロサービスの実装に関する情報を電子書籍「マイクロサービス」としてダウンロードすることもできます。 設計から展開まで。 また、マイクロサービス リファレンス アーキテクチャマイクロサービス ソリューション ページに関するシリーズもご覧ください。

ゲストブロガーの Chris Richardson 氏は、Amazon EC2 向けの初期の Java PaaS (Platform as a Service) であるオリジナルのCloudFoundry.comの創設者です。 彼は現在、アプリケーションの開発および展開方法の改善について組織にコンサルティングを行っています。 彼はまた、 http://microservices.ioでマイクロサービスに関するブログを定期的に書いています。


「このブログ投稿には、入手できなくなった製品やサポートされなくなった製品が参照されている場合があります。 利用可能な F5 NGINX 製品およびソリューションに関する最新情報については、 NGINX 製品ファミリーをご覧ください。 NGINX は現在 F5 の一部です。 以前の NGINX.com リンクはすべて、F5.com の同様の NGINX コンテンツにリダイレクトされます。"