マイクロサービス アーキテクチャは、小さな自律サービスのコレクションで構成されています。 各サービスは自己完結型であり、境界付けられたコンテキスト内で 1 つのビジネス機能を実装している必要があります。 境界付けられたコンテキストは、ビジネス内の自然な区分であり、ドメイン モデルが存在する明示的な境界を提供します。
マイクロサービスとは
マイクロサービスは小さく、独立的で、疎結合しています。 小規模な 1 つの開発者チームでサービスを作成および管理できます。
各サービスは個別のコードベースであり、小規模な開発チームで管理できます。
サービスは個別にデプロイできます。 チームは、アプリケーション全体を再構築したり再デプロイしたりすることなく、既存のサービスを更新できます。
サービスはサービスのデータや外部の状態を保持する役割を担います。 これは、個別のデータ層でデータを保持する従来のモデルと異なる点です。
サービスは、明確に定義された API を使用して、互いに通信します。 各サービス内部の実装の詳細は、他のサービスに開示されません。
ポリグロット プログラミングをサポートします。 たとえば、サービスは、同じテクノロジ スタック、ライブラリ、またはフレームワークを共有する必要はありません。
また、サービス自体については、いくつかの他のコンポーネントが次のような一般的なマイクロサービス アーキテクチャで使用されます。
管理/オーケストレーション。 このコンポーネントは、ノードへのサービスの配置、障害の特定、ノード間のサービスの再調整などを行う役割を担います。 通常、このコンポーネントは、カスタム ビルドではなく、Kubernetes などの既製テクノロジです。
API ゲートウェイ。 API ゲートウェイは、クライアントのエントリ ポイントです。 サービスを直接呼出す代わりに、クライアントは API ゲートウェイを呼び出し、それがその呼び出しをバック エンドの適切なサービスに転送します。
API ゲートウェイを使用することには次のようなメリットがあります。
サービスからクライアントを切り離します。 サービスのバージョン管理とリファクタリングを、すべてのクライアントを更新する必要なく行うことができます。
サービスは、AMQP などの Web フレンドリではないメッセージング プロトコルを使用できます。
API ゲートウェイは、認証、ログ記録、SSL 終了、負荷分散などの他の横断的な関数を実行できます。
調整、キャッシュ、変換、検証など、すぐに使用できるポリシー。
メリット
機敏性。 マイクロサービスは個別にデプロイされるため、バグ修正や機能リリースが管理しやすくなります。 アプリケーション全体を再デプロイしなくてもサービスを更新できるほか、問題が発生したときに更新プログラムをロールバックできます。 多くの従来のアプリケーションでは、アプリケーションの 1 つの部分でバグが見つかった場合、リリース プロセス全体が中止になる可能性があります。 新しい機能は、バグ修正を統合し、テストし、公開されるまで保留される可能性があります。
集中的な小規模チーム。 マイクロサービスの規模は小さく、1 つの機能チームによって構築、テスト、およびデプロイできます。 小規模なチーム編成により、機敏性が向上します。 大規模なチームでは、コミュニケーションに時間がかかり、管理オーバーヘッドが増大し、機敏性も低下するため、生産性が低くなる傾向があります。
小さなコード ベース。 モノリシック アプリケーションでは、時間の経過に伴ってコードの依存関係が複雑になる傾向があります。 新しい機能を追加するには、多くの場所でコード変更が必要です。 マイクロサービス アーキテクチャでは、コードまたはデータ ストアが共有されないため、依存関係を最小限に抑え、新しい機能を簡単に追加できます。
テクノロジの組み合わせ。 必要に応じて、チームがテクノロジ スタックを組み合わせて、サービスに最適なテクノロジを選択できます。
障害の分離。 個々のマイクロサービスが使用できなくなっても、上流マイクロサービスが障害を正しく処理するように設計されている限り、アプリケーション全体が中断されることはありません。 たとえば、サーキット ブレーカー パターンを実装したり、マイクロサービスが非同期メッセージング パターンを使用して相互に通信するようにソリューションを設計したりできます。
スケーラビリティ。 サービスは独立して拡大縮小できるため、アプリケーション全体をスケールアウトせずに、追加のリソースが必要なサブシステムをスケールアウトできます。 Kubernetes などのオーケストレーターを使用すると、より高密度なサービスを 1 つのホストに圧縮できるため、リソースをより効率的に使用できます。
データの分離。 影響を受けるのは 1 つのマイクロサービスだけであるため、スキーマ更新がはるかに実行しやすくなります。 モノリシック アプリケーションでは、スキーマの更新は非常に困難です。これは、アプリケーションの異なる部分がすべて同じデータに触れる可能性があり、スキーマの変更がリスクになるためです。
課題
マイクロサービスの利点は、何もせずに手に入るものではありません。 マイクロサービス アーキテクチャに着手する前に考慮すべき課題の一部を示します。
複雑さ。 マイクロサービス アプリケーションは、同等のモノリシック アプリケーションよりも多くの動的パーツで構成されています。 各サービスはより単純ですが、システム全体としてはより複雑です。
開発とテスト。 他の依存サービスに依存する小さいサービスを作成するには、従来のモノリシックまたは階層化アプリケーションを作成するのとは異なるアプローチが求められます。 既存のツールは、サービスの依存関係を処理するように設計されているとは限りません。 サービス間の境界を越えたリファクタリングは、難しい場合があります。 また、アプリケーションの進化が早い場合は特に、サービスの依存関係をテストすることは困難です。
ガバナンスの欠如。 マイクロサービスを構築する際に分散アプローチをとることにはメリットがありますが、問題が発生しやすくもなります。 多くのさまざまな言語やフレームワークを使用するために、アプリケーションの維持が難しくなることがあります。 チームの柔軟性を過度に制限することなく、プロジェクト全体に標準を導入することが有益な場合があります。 これは特に、ログ記録などの横断的な機能に適用されます。
ネットワークの輻輳と待機時間。 多くの小さく細分化されたサービスを使用すると、よりインタラクティブな通信が可能になります。 また、サービスの依存関係のチェーンが長すぎる (サービス A が B を呼び出し、その B が C を呼び出すなどの) 場合、追加される待機時間が問題になることがあります。 API は慎重に設計する必要があります。 過度な呼び出しが必要な API は避け、シリアル化形式について検討し、キューベースの負荷平準化など、非同期通信パターンを使用する場所を探してください。
データ整合性。 各マイクロサービスで、独自データの永続化を行う必要があります。 その結果、複数のサービス間でのデータの整合性が課題となる可能性があります。 さまざまなサービスがさまざまなタイミングで、さまざまなテクノロジーを使用してデータを永続化しますが、それぞれに成功レベルが異なる可能性があります。 新しいデータまたは変更されたデータの永続化に複数のマイクロサービスが関与している場合、完全なデータ変更が ACID トランザクションと見なされる可能性は低くなります。 どちらかといえば、この手法は BASE (Basically Available、Soft state、Eventually consistent) に沿ったものになります。 可能であれば、最終的な整合性を優先します。
管理。 マイクロサービスを成功させるには、成熟した DevOps カルチャが必要です。 サービス間で相互に関連付けられたログを記録することは難しい場合があります。 通常、ログ記録は単一のユーザー操作を要求するために複数のサービスの呼び出しを関連付ける必要があります。
バージョン管理。 サービスの更新プログラムは、依存しているサービスを中断してはいけません。 複数のサービスが特定の時点で更新される場合があるため、慎重に設計しないと下位互換性または上位互換性に問題が生じる可能性があります。
スキル セット。 マイクロサービスは高度な分散システムです。 成功のために必要なスキルと経験がチームにあるかどうかを慎重に評価してください。
ベスト プラクティス
ビジネス分野周辺のモデル サービス。
すべてを分散化します。 個々のチームがサービスの設計と構築を担います。 コードまたはデータのスキーマを共有しないようにします。
データ ストレージは、そのデータを所有するサービス専用にする必要があります。 各サービスとデータの種類に最適なストレージを使用します。
サービスが、適切に設計された API を介して通信するようにします。 実装の詳細が漏えいしないようにします。 API は、サービス内部の実装ではなく、ドメインをモデル化する必要があります。
サービス間の結合は行わないようにします。 結合の原因には、共有データベース スキーマや固定の通信プロトコルなどがあります。
認証や SSL 終了などの横断的な懸念事項をゲートウェイにオフロードします。
ドメインのナレッジをゲートウェイの外部で保持します。 ゲートウェイは、ビジネス ルールやドメイン ロジックのナレッジを使用せずに、クライアントの要求を処理し、ルーティングする必要があります。 そうしなければ、ゲートウェイが依存関係となり、サービス間の結合が生じる可能性があります。
サービスには、疎結合と機能の高い凝集度が必要です。 まとめて変更される可能性がある機能は、まとめてパッケージ化してデプロイする必要があります。 それらの機能が別々のサービスに格納された場合、1 つのサービスの変更には他のサービスの更新が必要であるため、結果として密接に結合されることになります。 2 つのサービス間で過度に通信が行われると、密接な結合と低い凝集度の問題が生じる可能性があります。
障害を分離します。 回復性戦略を使用して、サービス内の障害が連鎖しないようにします。 「Resiliency patterns」(回復性のパターン) のページと信頼性の高いアプリケーションの設計に関するページをご覧ください。
次のステップ
Azure でのマイクロサービス アーキテクチャの構築に関する詳細なガイダンスいついては、「Azure でのマイクロサービスの設計、構築、および操作」をご覧ください。