コンテンツにスキップ

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

はじめに

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


01. アーキテクチャ概要

アーキテクチャの歴史

architecture_history

年代 アーキテクチャ 説明 補足
1999 モノリシックアーキテクチャ 1999年台、バックエンドのアーキテクチャとしてモノリシックアーキテクチャが台頭していた。しかし、モノリシックアーキテクチャは無秩序でつぎはぎだらけのアプリケーションになることが論文 (『大きな泥だんご』) で指摘された。 https://en.wikipedia.org/wiki/Big_ball_of_mud
2000 〜 2004 サービス指向アーキテクチャ モノリシックアーキテクチャの批判を受け、〇〇 (提唱者が見つからず) がアプリケーションを機能の粒度で分割するアーキテクチャを提唱した。ただ『機能』という粒度が抽象的で、概念としては提唱されていても、実装方法の確立にまでは至らなかった。 https://en.wikipedia.org/wiki/Service-oriented_architecture
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


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 Gateway

microservices_api-gateway-pattern

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

  • 受信した通信を適切なマイクロサービスのAPIにルーティング
  • 認証
  • トレースIDの付与
  • キャッシュの作成
  • リクエスト制限


分割パターン

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

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

▼ Public API

マイクロサービスにリクエストを送信するアプリケーションの種類に関係なく、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を分割する。

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

記入中...


実装パターン

▼ 自前で実装

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

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

▼ OSSを使用

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

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

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

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

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

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