コンテンツにスキップ

マイクロサービスアーキテクチャ@アーキテクチャ

はじめに

本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。


01. アーキテクチャ概要

アーキテクチャの歴史

architecture_history

年代 アーキテクチャ 説明 補足
1999 モノリシックアーキテクチャ 1999年台、バックエンドのアーキテクチャとしてモノリシックアーキテクチャが台頭していた。しかし、モノリシックアーキテクチャは無秩序でつぎはぎだらけのアプリケーションになることが論文 (『大きな泥だんご』) で指摘された。 https://en.wikipedia.org/wiki/Big_ball_of_mud
2000 〜 2004 サービス指向アーキテクチャ 1999後半〜2000前半に、Thomas Erlらがアプリケーションを機能の粒度で分割するアーキテクチャを提唱した。ただ『機能』という粒度が抽象的で、概念としては提唱されていても、実装方法の確立にまでは至らなかった。 https://en.wikipedia.org/wiki/Service-oriented_architecture
https://www.serviceorientation.org/p0.html
https://www.amazon.com/dp/0470141115
2014 マイクロサービスアーキテクチャ 2014年にThoughtWorks社は、サービス指向アーキテクチャとドメイン駆動設計を統合し、アプリケーションを独立したマイクロサービスの集まりに分割するアーキテクチャを提唱した。サービス指向アーキテクチャにドメイン駆動設計の高凝集/低結合の考え方を取り入れることで、実装可能な理論に昇華させた。 https://martinfowler.com/articles/microservices.html
https://atmarkit.itmedia.co.jp/ait/articles/2110/22/news006.html
2017 ミニマイクロサービスアーキテクチャ マイクロサービスアーキテクチャのマイクロサービス自体を独立したモノリスなアプリケーションと捉えると、その分だけ開発チーム (マネージャーとエンジニア) が必要になってしまう。2017年にCloud Elements社は、これに対処するためにミニマイクロサービスアーキテクチャを提唱した。このアーキテクチャでは、マイクロサービスアーキテクチャとモノリスアーキテクチャの間をとった粒度で、アプリケーションを複数のマイクロサービスに分割する。この粒度を、マイクロサービスに対抗して『ミニマイクロサービス』または『MASA』とよぶ。 https://blog.cloud-elements.com/pragmatic-microservices-architecture
https://atmarkit.itmedia.co.jp/ait/articles/2110/22/news006.html
2018 モジュラーモノリスアーキテクチャ ミニマイクロサービスアーキテクチャではマイクロサービスの粒度が大きくなったものの、複数のマイクロサービスが必要になることは変わらず、その分だけ開発チームが必要になる問題は解決されなかった。そこで、Root Insurance社はモジュラーモノリスを提唱した。モジュラモノリスでは、マイクロサービスアーキテクチャとモノリスアーキテクチャの間をとった粒度で、アプリケーションを細かいモジュールに分割する。最初、モジュラーモノリスとして設計し、マイクロサービスアーキテクチャに移行していくという選択肢もある。 https://medium.com/@dan_manges/the-modular-monolith-rails-architecture-fb1023826fc4
https://creators-note.chatwork.com/entry/2020/12/02/090000
https://eh-career.com/engineerhub/entry/2022/07/25/093000


各アーキテクチャの粒度の比較

architecture_deployment_comparison

モジュールの大きさ 粒度名 説明
一番大きい モノリシック アプリケーションのモジュールが分割されておらず、アプリケーションをデプロイの単位とする。
モジュラー アプリケーションがモジュールに分割されており、アプリケーションをデプロイの単位とする。モジュール間のデータのやり取りに通信を使用するか否かや、モジュール間でDBを共有するか否かの選択によって、作成パターンがいくつかある。
https://scrapbox.io/tsuwatch/%E3%83%A2%E3%83%8E%E3%83%AA%E3%82%B9%E3%81%A8%E3%83%9E%E3%82%A4%E3%82%AF%E3%83%AD%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%AE%E3%81%82%E3%81%84%E3%81%A0
ミニマイクロサービス アプリケーションがサブドメイン (または境界づけられたコンテキスト) を単位としたマイクロサービスに分割されており、アプリケーションを構成するマイクロサービスのある程度のまとまりをデプロイの単位とする。また、DBを各マイクロサービスで共有する。
一番小さい マイクロ アプリケーションがサブドメイン (または境界づけられたコンテキスト) を単位としたマイクロサービスまたはルートエンティティに分割されており、アプリケーションを構成するマイクロサービスそれぞれをデプロイの単位とする。また、DBを各マイクロサービスで共有せずに、マイクロサービスごとに配置する。


プレゼンテーションドメイン分離

モノリシックの段階では、フロントエンドとバックエンドが1つのアプリケーションで密結合になっている。

フロントエンドとバックエンドを分離した段階では、フロントエンドとバックエンドが異なるアプリケーションとして分離される。

マイクロサービスでの段階では、さらにバックエンドが複数のアプリケーションとAPIアグリゲーション層に分離される。

presentation_domain_separation


関連パターン

▼ 関連パターンとは

マイクロサービスアーキテクチャでは固有の問題が起こる。

これを解決するための関連パターンがたくさんある。

microservices_related-patterns

*実装例*

microservices.ioサイトで紹介しきれていない実装方法は、softwarepatternslexiconサイトで確認できる。

▼ マイクロサービスアーキテクチャとクラウドネイティブ

優れたクラウドネイティブアプリケーションを作成するには、マイクロサービスアーキテクチャとクラウドネイティブ技術が必要である。

microservices_cloud-native

マイクロサービスアーキテクチャの関連パターンは、クラウドネイティブ技術で代替できる。

マイクロサービスの関連パターン クラウドネイティブ技術
Externalized configuration Kubernetes ConfigMap、Kubernetes Secret
サービスディスカバリー Kubernetes Service
負荷分散 Kubernetes Service
API Gateway Kubernetes Ingress
集中ロギング Fluentd
集中メトリクス Prometheus、Grafana
分散トレース OpenTelemetry、Grafana Tempo
回復力 Kubernetes Probe、Istio
自己回復 Kubernetes Deployment
... ...


01-02. マイクロサービスアーキテクチャ

特徴

▼ ビジネスのスケーリングに強い

ビジネスがスケーリングする時、マイクロサービスの新規実装または削除を行えば良いため、ドメイン層の激しい変化に強い。

▼ コンウェイの法則が働く

マイクロサービスアーキテクチャにより、組織構造が小さなチームの集まりに変化することを期待できる。

▼ 高頻度でリリース可能

各マイクロサービスを独立してデプロイできるため、高頻度でリリースできる。

▼ 障害の影響が部分的

いずれかのマイクロサービスに障害が発生したとして、サーキットブレイカーを使用することにより、ダウンストリーム側マイクロサービスへの障害の波及を食い止められる。

そのため、障害の影響が部分的となり、アプリケーション全体が落ちてしまうことがない。

▼ 複数の開発言語を使用可能

マイクロサービス間で、共通のデータ記述言語を使用してデータ通信を行えば、各マイクロサービスの開発言語が異なっていても問題ない。


アーキテクチャ例

▼ Eコマース (Googleのサンプル)

srcディレクトリに各マイクロサービスのディレクトリを配置する。

  • カート
  • 商品検索とインデックス
  • 通貨の変換
  • クレジットカード
  • 送料と発送
  • 注文確認メール
  • 注文フロー
  • レコメンド
  • 広告
  • 合成監視

service_google

▼ Eコマース (メルカリのサンプル)

servicesディレクトリに各マイクロサービスのディレクトリを配置する。

  • 認証
  • カタログ
  • 顧客
  • 商品

service_mercari

▼ Eコマース (Datadogのサンプル)

  • 広告
  • 割引

▼ Eコマース (Amazon)

service_twitter

▼ SNS (Twitter)

service_twitter

▼ 地図 (Google Map)

service_google-map


フレームワーク

マイクロサービスアーキテクチャのフレームワークとして、Dapr、Axon、Eventuate、MicroProfile LRAなどがある。


02. ドメイン層

マイクロサービス

▼ マイクロサービスとは

anti-corruption-layer

マイクロサービスアーキテクチャにおける分散システム状のバックエンドのコンポーネントのこと。

特定のマイクロサービスが他のマイクロサービスに侵食され、マイクロサービスの凝集度が低くならないようにするために、ACL:Anti Corruption Layer (腐食防止レイヤー) を設ける必要がある。

腐食防止レイヤーは、異なるコンテキストから受信したデータを、そのマイクロサービスのコンテキストにあったデータ形式に変換する責務を持つ。

CQRSでは、これはプロセスマネージャパターンとして知られている。

一方でSagaパターンとも呼ばれるが、分散トランザクションでも同じ用語があるため、混乱を避けるためにプロセスマネージャパターンとする。

▼ 各マイクロサービスのアーキテクチャ

各マイクロサービスのアーキテクチャは自由である。

この時、ドメイン駆動設計のアーキテクチャを基に実装できる。

*例*

ECサイトがあり、これの商品販売ドメインを販売サブドメインと配送サブドメインに分割できるとする。

この時、それぞれのサブドメインの問題を解決する販売コンテキストと配送コンテキストをマイクロサービスの粒度となり、オニオンアーキテクチャのアプリケーション間で同期通信/非同期通信を実行する。

microservices-architecture_onion-architecture


分割パターン

▼ サブドメイン単位/境界づけられたコンテキスト単位

サブドメインまたは境界づけられたコンテキストを単位として、マイクロサービスを分割とする。

現状のモノリスの分割段階 境界づけられたコンテキスト サブドメイン 機能単位
すでにサブドメインに分割されている 不可 不可 記入中...
すでに複数のサブドメインを含む境界づけられたコンテキストに分割されている 不可 記入中...
すでに単一のサブドメインを含む境界づけられたコンテキストに分割されている 記入中...

解決領域となる境界づけられたコンテキストがサブドメインの中に1個しか含まれていない場合は、境界づけられたコンテキストでマイクロサービスを分割することになる。

図にて、境界づけられたコンテキスト間で、『利用者』という名詞に対する定義づけ/意味合いが異なっていることに留意する。

ドメイン駆動設計では境界づけられたコンテキストが1個のアプリケーションに相当するため、境界づけられたコンテキストで分割した場合、マイクロサービスアーキテクチャは複数のアプリケーションから構成されるアーキテクチャと捉えられる。

加えて小さな粒度に分割する方法として、ルートエンティティを粒度ともできる。

service_bounded-context

▼ ルートエンティティ単位 (エンティティサービス)

『エンティティサービス』ともいう。

ドメイン層のルートエンティティを単位として、マイクロサービスを分割する。

この場合、境界づけられたコンテキストよりもマイクロサービスの粒度が小さい。

そのため、複数のマイクロサービスで1つの境界づけられたコンテキストを構成することになり、異なるマイクロサービスが同じ種類のデータを持つオブジェクトを処理する。

ドメイン層にはマイクロサービス (例:〇〇ドメインサービス) があり、ドメイン層以外のレイヤー (インターフェース層、ユースケース層、リポジトリ層) はマイクロサービスではない。

DBレコードの書き込み/読み出しのトランザクションをルートエンティティ単位で実行するため、マイクロサービスの単位がわかりやすい。

一方で、データに着目したステートソーシングパターンのルートエンティティを使用することはアンチパターンである。

最良な解決策として、振舞に着目したイベントソーシングを使用する必要がある。

また、各マイクロサービスを名詞ではなく動詞 (例:〇〇管理サービス、〇〇中継サービス、〇〇通知サービス、〇〇集計サービス) で命名すると良い。

その他、各マイクロサービスでDBを完全に独立させることや、SAGAパターンを使用すること、がある。


分割アンチパターン

▼ 分散モノリス

複数のマイクロサービスをセットでデプロイしなければならず、マイクロサービス間のデプロイが独立していないような分割パターン。

例えば、マイクロサービス間で重複するロギングライブラリをマイクロサービスとして分離した結果、複数のマイクロサービスがこのロギングマイクロサービスに依存してしまうような場合がある。

分散モノリスにならないように、マイクロサービス間で使用するライブラリが重複することを許容する必要がある。


03. リポジトリ層

分割パターン

▼ ドメイン層と同じマイクロサービス

ドメイン層と同じマイクロサービス内で実行する。

最も一般的な分割パターンである。

▼ ドメイン層とは異なるマイクロサービス + 占有リポジトリ単位 (ルートエンティティ単位)

ドメイン層とは異なるマイクロサービス内で実行する。

また、占有リポジトリを単位として、マイクロサービスを分割する。

ドメイン駆動設計では、DBレコードの書き込み/読み出しのトランザクションをルートエンティティ単位で実行する。

そのため、リポジトリは実際にはルートエンティティに対応しており、ルートエンティティ単位で分割すると言い換えても良い。

▼ ドメイン層とは異なるマイクロサービス + 共有リポジトリ単位 (ルートエンティティ単位)

ドメイン層とは異なるマイクロサービス内で実行する。

また、共有リポジトリを単位として、マイクロサービスを分割する。

ただ、境界づけられたコンテキストは他のコンテキストとは異なるルートエンティティを持つため、リポジトリも完全に独立しているはずである。

そのため、異なる境界づけられたコンテキストのマイクロサービスが、同じリポジトリを共有することは起こらないはずである。

逆に言うと、複数のマイクロサービスがリポジトリを共有している場合、それらのマイクロサービスは同じコンテキストに属しており、分割する必要がないということになる。

これらのことから、この分割パターンはあまり良くない (出典は俺) 。


04. APIアグリゲーション層

APIアグリゲーション層とは

全てのAPIまたは複数のAPIのセットとして機能する。


04-02. API Gateway

API Gatewayとは

microservices_api-gateway-pattern

クリーンアーキテクチャでいうインフラストラクチャ層とインターフェース層のような機能を担う。

主要な機能として、受信した通信を適切なマイクロサービスのAPIにルーティング

  • ルーティング
  • 認証
  • トレースIDの付与
  • キャッシュの作成
  • リクエストのレートリミット
  • 通信の暗号化
  • ...

なお、API Gatewayをサービスメッシュに参加させることで、これらの機能の一部 (認証、トレースIDの付与、通信の暗号化、リクエスト制限) をサイドカーに委譲できる。


分割パターン

▼ API Gatewayの分割パターンとは

API Gatewayの責務をどのように分割するかに応じて、分割パターンがある。

▼ Central Aggregating Gateway

マイクロサービスにリクエストを送信するアプリケーションの種類に関係なく、API Gatewayを1個だけ作成する。

apigateway_public-api-pattern

▼ BFF:Backends For Frontends

マイクロサービスにリクエストを送信するクライアントアプリケーションの種類 (Webアプリケーション、モバイルアプリケーション、他社向けアプリケーションなど) を単位として、API Gateway (Web API Gateway、Mobile API Gateway、他社向けAPI Gatewayなど) を作成する。

ただし、ドメインによっては同じクライアントアプリケーションの種類であっても、API Gatewayを分割することもある。

例えば、送金ドメインであれば、クライアントアプリケーションには銀行ダイレクトアプリや銀行系決済サービスアプリがあり、これらが同じモバイルアプリケーションであっても、API Gatewayを分割する。

なお、BFFはRESTful-APIであってもGraphQL-APIであっても、どちらでも問題ない。

apigateway_bff-pattern

▼ Federated Gateway

BFFではアプリケーションの種類ごとにAPI Gatewayを作成したが、Federated Gatewayでは各API Gatewayのエンドポイントを統合する。


API形式パターン

▼ API GatewayのAPI形式パターンとは

API GatewayのAPI形式に応じて、分割パターンがある。

▼ RESTful-API

記入中...

▼ GraphQL-API

記入中...

▼ RPC-API

記入中...


責務パターン

▼ Gateway Offloadingパターン

API Gatewayは、マイクロサービス間で共通する課題 (認証、ロギング、SSL証明書など) を処理する責務を持ちます。

▼ Gatewayルーティングパターン

API Gatewayは、複数のマイクロサービスにリクエストをルーティングする責務を持ちます。

▼ Gatewayアグリゲーターパターン

API GatewayにAPI Compositionを適用した方法である。


実装パターン

▼ 自前で実装する場合

API Gatewayを自前 (例:フルスクラッチ、GraphQLを使用したフルスクラッチなど) で実装する。

Kubernetes内で管理できるメリットがある。

GraphQLでAPI Gatewayを実装する場合は、特に注意が必要である。

フロントエンドとAPI Gatewayの両方でGraphQL特有の実装が必要になるので、フロントエンドとAPI Gatewayの開発が分業にしくくなってしまう。

ただ、フロントエンドとAPI Gatewayの開発チームの両方がGraphQLの知識を持ってれば、これは起こらない。

▼ OSSを使用する場合

API GatewayのOSS (Kong、Tyk、Apigee、Kuma、Nginx、Envoy、Apache APISIXなど) を使用する。

Kubernetes内で管理できるメリットがある。

▼ クラウドプロバイダーのマネージドサービスを使用する場合

クラウドプロバイダー (例:AWS、Google Cloud) が提供するAPI Gateway (例:AWS API Gateway、Google API Gateway) を使用する。

クラウドプロバイダーの対応状況によっては、Kubernetes内で管理できない可能性がある。

その場合、フロントエンドアプリケーションがAPI Gatewayに通信できるように、フロントエンドアプリケーションとバックエンドアプリケーションを異なるKubernetesで動かす必要がある。