マイクロサービス単位のデータ管理
ヒント
このコンテンツは eBook の「コンテナー化された .NET アプリケーションの .NET マイクロサービス アーキテクチャ」からの抜粋です。.NET Docs で閲覧できるほか、PDF として無料ダウンロードすると、オンラインで閲覧できます。
マイクロサービス アーキテクチャの重要なルールは、各マイクロサービスがそのドメイン データとロジックを所有する必要があるということです。 完全なアプリケーションはそのロジックとデータを所有するしますが、それと同様に、各マイクロサービスは、マイクロサービスごとに独立した展開を持ち、自律的なライフサイクルでロジックとデータを所有している必要があります。
つまり、サブシステムとマイクロサービスとの間で、ドメインの概念モデルが異なるものになります。 顧客関係管理 (CRM) アプリケーション、取引購買サブシステム、顧客サポート サブシステムから成るエンタープライズ アプリケーションがあるとします。ここで、各アプリケーションやサブシステムは、それぞれ特有の顧客エンティティ属性やデータを呼び出し、異なる境界コンテキスト (BC) を利用します。
この原則は、ドメイン駆動型設計 (DDD) でも同様です。DDD の場合、各境界コンテキスト、自律サブシステム、自律サービスは、独自のドメイン モデル (データ + ロジックと動作) を所有する必要があります。 各 DDD 制限コンテキストは、1 つのビジネス マイクロサービス (1 つまたは複数のサービス) と関連しています 次のセクションでは、境界コンテキスト パターンのこの点について詳しく説明します。
一方、多くのアプリケーションで使用されている従来の (モノリシックなデータ) アプローチは、単一の中央のデータベースまたはごく少数のデータベースを持つ方法です。 図 4-7 に示すように、多くの場合、これは正規化された SQL Server です。アプリケーション全体とその内部にあるすべてのサブシステムに使用されます。
図 4-7. データ管理の比較: モノリシック データベースとマイクロサービス
従来のアプローチでは、すべてのサービスが、通常は 1 つの階層型アーキテクチャ内で 1 つのデータベースを共有していました。 マイクロサービスのアプローチでは、各マイクロサービスがそのモデル/データを所有しています。 中央のデータベース アプローチは、最初は単純に思え、さまざまなサブシステムでエンティティを再利用してすべての一貫性を保てるように思えます。 しかし、実際は、多くの異なるサブシステムにサービスを提供する、ほとんどの場合に必要のない属性や列を含んだ大きなテーブルを用意することになります。 これは、短い散歩にも、日帰りドライブにも、地理の勉強にも、同じ縮尺の地図を利用するようなものです。
通常は単一のリレーショナル データベースを使用するモノリシック アプリケーションには、ACID トランザクションと SQL 言語という 2 つの重要な利点があります。このいずれも、アプリケーションに関連するすべてのテーブルとデータを処理します。 このアプローチを利用すると、複数のテーブルのデータを結合するクエリを簡単に記述することができます。
一方、マイクロサービス アーキテクチャに移行すると、データ アクセスは、はるかに複雑になります。 マイクロサービス内または有界コンテキスト内で ACID トランザクションを使用する場合でも、各マイクロサービスによって所有されるデータは、そのマイクロサービスのみがアクセスでき、その API エンドポイント (REST、gRPC、SOAP など) を介した同期的な方法、またはメッセージング (AMQP またはこれに類するもの) を介した非同期的な方法のいずれかでのみアクセスする必要があります。
データをカプセル化することで、マイクロサービス間の結合は弱くなり、相互に独立して進化できます。 複数のサービスが同じデータにアクセスしている場合、スキーマの更新にはすべてのサービスに対する更新を調整する必要があります。 これではマイクロサービスのライフサイクルの自律性が失われます。 ただし、分散データ構造なので、マイクロサービス全体で単一の ACID トランザクションは作成できません。 つまり、ビジネス プロセスが複数のマイクロサービスにまたがる場合、最終的な整合性を使用する必要があります。 これは、後述するとおり、別のデータベース間で整合性制約を作成したり、分散トランザクションを使用したりできないので、単純な SQL 結合を実装するよりも困難になります。 同様に、その他の多くのリレーショナル データベース機能も、複数のマイクロサービス間で使用できません。
さらに進んで、複数のマイクロサービスがさまざまな種類のデータベースを使用することもよくあります。 最新のアプリケーションではさまざまなデータを格納して処理するので、リレーショナル データベースは常に最善の選択肢とはなりません。 一部のユース ケースでは、Azure CosmosDB や MongoDB などの NoSQL Server の方が、SQL Server や Azure SQL Database などの SQL Server よりもデータ モデルが便利で、パフォーマンスとスケーラビリティが高い場合があります。 また、リレーショナル データベースが最善のアプローチのケースもあります。 そのため、マイクロサービスベースのアプリケーションでは、SQL と NoSQL のデータベースが混在することがよくあります。これは多言語永続化アプローチと呼ばれることもあります。
データ格納用のパーティション分割された多言語永続化アーキテクチャには、多くの利点があります。 たとえば、疎結合されたサービス、パフォーマンス、スケーラビリティ、コスト、管理容易性などです。 ただし、この章で後述するドメインモデルの境界の特定のように、分散データ管理の課題がいくつか生じる可能性があります。
マイクロサービスと境界コンテキスト パターンの関係
マイクロサービスの概念は、ドメイン駆動型設計 (DDD) の境界コンテキスト (BC) パターンに由来しています。 DDD は、モデルを複数の BC に分割し、その境界を明示的にすることで大規模なモデルを扱っています。 各 BC は独自のモデルとデータベースを持つ必要があります。同様に、各マイクロサービスはその関連データを所有しています。 さらに各 BC には、ソフトウェア開発者とドメイン専門家の間のコミュニケーションに役立つ独自のユビキタス言語が存在するのが一般的です。
異なるドメイン エンティティが同じ ID (つまり、ストレージからエンティティを読み取るために使用される一意の ID) を共有している場合でも、ユビキタス言語で使われる用語 (主にドメイン エンティティ) は、境界コンテキストによって名前が異なる可能性があります。 たとえば、"ユーザー プロファイル" 境界コンテキストの "ユーザー" ドメイン エンティティが、"注文" 境界コンテキストの "購入者" ドメイン エンティティと ID を共有する可能性があります。
そのため、マイクロサービスは境界コンテキストと似ていますが、分散サービスであることも指定されています。 これは境界コンテキストごとに個別のプロセスとして構築されます。また、前述のように分散プロトコル (HTTP/HTTPS、WebSockets、AMQP など) を使用する必要があります。 ただし、境界コンテキスト パターンでは、境界コンテキストが分散サービスか、モノリシック展開アプリケーション内の単なる論理的な境界 (汎用サブシステムなど) かは指定されません。
各境界コンテキストに対してサービスを定義することを出発点にすることを強くお勧めします。 ただし、設計で無理にそうする必要はありません。 場合によっては、いくつかの物理サービスで構成された境界コンテキストまたはビジネス マイクロサービスを設計する必要があります。 ただし最終的には、境界コンテキストとマイクロサービスの両方のパターンが密接に関連することになります。
DDD は、分散型マイクロサービスの形で実際の境界を獲得することで、マイクロサービスの利点を活用しています。 ただし、マイクロサービス間でモデルを共有しないようなアイデアの場合は、境界コンテキストでも実現できます。
その他のリソース
Chris Richardson。 パターン: サービスごとのデータベース
https://microservices.io/patterns/data/database-per-service.htmlMartin Fowler。 BoundedContext
https://martinfowler.com/bliki/BoundedContext.htmlMartin Fowler。 PolyglotPersistence
https://martinfowler.com/bliki/PolyglotPersistence.htmlAlberto Brandolini。 コンテキスト マッピングを使用した戦略的ドメイン駆動設計
https://www.infoq.com/articles/ddd-contextmapping
.NET