皆様、こんにちは!
アイレット株式会社 DX開発事業部の楊林と申します。
前回の投稿では、Google Cloud でサービスを定義する際によく用いられるいくつかの方法と、重要な指標について整理しました。
今回は、Google Cloud におけるマイクロサービスの設計方法とアーキテクチャについて整理していきます。
マイクロサービス
マイクロサービスはモノリシックアプリケーションと異なり、大規模なプログラムを独立した複数の小さなサービスに分割する設計手法です。
モノリシックアプリケーションは単一のコードベースにすべての機能を実装し、1つのデータベースにすべてのデータを格納します。一方でマイクロサービスでは、機能ごとにサービスを分離し、それぞれを独立して開発・デプロイできるようにします。
マイクロサービスのアーキテクチャを選択する主な理由の一つは、複数のチームがそれぞれ独立して作業し、各チームのペースで本番環境に到達できる点にあります。これにより組織のスケーリングに対応しやすくなり、チーム数の増加に合わせて開発スピードを維持できます。また、要件に基づいて個別のマイクロサービスをスケーリングできる点も大きな利点です。
アーキテクチャの観点から見ると、モノリスとして設計する場合でも、マイクロサービスを中心としたアプリケーションでも、境界を明確に定義したモジュール式のコンポーネントで構成する必要があります。モノリスではすべてのコンポーネントをデプロイ時にまとめてパッケージ化しますが、マイクロサービスではコンポーネントを個別にデプロイできます。
Google Cloud にはマイクロサービスのデプロイを容易にするコンピューティングサービスがいくつか用意されています。たとえば App Engine、Cloud Run、GKE、Cloud Functions などがあり、それぞれ提供する抽象度や制御レベルが異なります。
サービスの独立性を実現するためには、各サービスがそれぞれ専用のデータストアを持つ設計が重要です。これにより各サービスに最適なデータストアソリューションを選択でき、サービスの独立性を維持できます。データストアを介してサービス同士が強く結合する設計は、可能な限り避けるべきです。
マイクロサービスアーキテクチャには以下のような強みがあります。
- さまざまなマイクロサービスの間に厳密なコントラクトを定義できる
- ロールバックを含む独立したデプロイサイクルを実現できる
- サブシステム単位での A/B リリーステストを同時に実行できる
- テスト自動化と品質保証に伴うオーバーヘッドを最小化できる
- ロギングとモニタリングの可視性を向上できる
- サービス単位でより詳細なコスト把握が可能になる
- 小さな単位でスケーリングすることで、全体のスケーラビリティと信頼性を高められる
一方で、以下のような課題も伴います。
- 開発とデプロイの独立性を保つためのサービス境界の定義は容易ではない
- インフラストラクチャが複雑化し、障害点が増える
- ネットワーク越しの通信によりレイテンシが増加する
- 障害や遅延を前提としたレジリエンス設計が必要になる
- サービス間通信のセキュリティ確保により運用負荷が増す
- サービスを個別にデプロイできる反面、API のバージョニングや下位互換性の維持が重要になる
アプリケーションを設計する際、技術面で特に難しいのがアプリケーションをどのようにマイクロサービスへ分解するかという点です。機能を論理的なグループに分ける際には、ドメインドリブン設計などの手法が非常に有効です。依存関係を最小限に抑えるよう、機能別または機能グループ別に分解します。
各マイクロサービスの内部はアーキテクチャレイヤ別に構成され、個別にデプロイ・スケーリングできるように設計されます。複数のアプリケーションから利用される共有サービスは分離し、独立してデプロイします。
設計上は、マイクロサービス自体を可能な限りステートレスに保つ方が管理は容易になります。状態を持たないことでスケーリングや新バージョンへの移行が容易になるためです。ただし、実際のマイクロサービスベースのアプリケーションでは、どこかの時点でステートフルなサービスを使用せざるを得ないケースが多くなります。そのため、ステートフルサービスがアーキテクチャ全体に与える影響を理解しておくことが重要です。
12要素App
12要素Appは、ウェブアプリケーションやSaaSアプリケーションを構築するための一連のベストプラクティスです。
12要素の設計を採用することで、アプリケーションをコンポーネントとして分離しやすくなり、継続的デプロイを前提とした設計が可能になります。また、スケールアップやスケールダウンを前提としたクラウドネイティブな運用にも適しています。
これらの特性はプログラミング言語やソフトウェアスタックに依存しないため、12要素の設計はさまざまなアプリケーションに適用できます。
12要素:
- コードベース:Gitなどのバージョン管理でトラッキングする必要があります。Google Cloud では Cloud Source Repositories のようなプライベートリポジトリを利用できますが、重要なのは「単一のコードベースを明確にバージョン管理する」という原則そのものです。
- 依存関係:考慮すべきことは、依存関係の宣言と分離です。依存関係は明示的に宣言し、バージョン管理の対象とする必要があります。言語固有のツールを用いて依存関係を管理します。
- 構成:どのアプリケーションにも、テスト、本番、開発など環境ごとの構成があります。デプロイの柔軟性を確保するため、この構成はコードの外部、通常は環境変数として管理します。
- バッキングサービス:データベース、キャッシュ、メッセージサービスなどのバッキングサービスは、URL や接続情報を通じてアクセスし、構成として設定する必要があります。
- ビルド、リリース、実行:ソフトウェアのデプロイプロセスは、ビルド、リリース、実行の3つの独立したステージに分ける必要があります。各ステージでは、それぞれ一意に識別可能な成果物が生成されます。
- プロセス:アプリケーションは1つ以上のステートレスなプロセスとして動作します。状態が必要な場合は、アプリケーションプロセスの外部で管理し、マイクロサービス概要で述べたような状態管理の手法を用いる必要があります。
- ポートバインディング:サービスはポート番号を使用して自らを公開する必要があります。アプリケーションはウェブサーバー機能を自身に内包し、外部の常駐型ウェブサーバーに依存しません。
- 同時実行:新しいプロセスを起動し、要求や負荷に応じて増減させることで、アプリケーションを水平スケールできる必要があります。
- 廃棄可能性:アプリケーションは、実行基盤となるインフラストラクチャの一時的な障害を前提として設計される必要があります。
- 開発環境と本番環境の類似性:本番環境で使用するものと可能な限り同一の環境を、開発・テスト・ステージング環境でも使用することが目的です。
- ログ:ログはアプリケーションの状態を把握するための重要な手段です。アプリケーションのコアロジックと、ログの収集・処理・分析は分離する必要があります。
- 管理者プロセス:管理者プロセスは通常、一時的に実行されるものであり、アプリケーションの通常プロセスとは分離する必要があります。
REST
優れたマイクロサービス設計は、疎結合であるべきです。
クライアントは URI、リクエストおよびレスポンスのメッセージ形式など、最小限の情報を知っていればサービスを利用できます。
サービスは多くの場合、HTTP 経由でテキストベースのペイロードを使用して通信します。
クライアントは GET、POST、PUT、DELETE などの HTTP メソッドを用いてリクエストを送信します。
リクエスト本文は JSON や XML などの形式で表現されます。
レスポンスも JSON、XML、HTML などの形式で返されます。
サービスは、既存のクライアントに影響を与えずに機能を拡張できる必要があります。
そのため、レスポンスには要素を追加することはあっても、既存の要素を削除しない設計が求められます。
このように、REST アーキテクチャは疎結合なシステム設計を支援します。
REST 自体は特定のプロトコルに依存する概念ではありませんが、実装としては HTTP が最も一般的に利用されます。一方で、マイクロサービス間通信などでは gRPC のような別の通信方式が選択されるケースもあります。
REST では、クライアントとサーバーが「リソースの表現」を交換します。
リソースとは情報を抽象的に表したものであり、リソースの表現とは、その時点におけるリソース情報の具体的な表現です。URI を用いてリソースにアクセスし、リクエストを送信すると、そのリソースの表現が通常は JSON 形式で返されます。
リクエストされるリソースは、単一のアイテムである場合も、複数のアイテムをまとめた集合である場合もあります。
パフォーマンスの観点から、個別に取得するよりも、複数のリソースをまとめて返す方が有効なケースもあります。このような設計は一般にバッチ API と呼ばれます。
REST をサポートするサービスは HTTP(S) を利用して Web 上で通信します。
リソースは URI、あるいはエンドポイントによって識別されます。
リクエストに対するレスポンスとして、リソース情報の表現が返されます。
REST アプリケーションは、一貫性のある統一されたインターフェースを提供します。
追加のリソースへのリンクを、レスポンスの一部として含めることも可能です。
また、パフォーマンス向上のためにキャッシュを活用し、不変なリソースについては最適化を検討します。
クライアントとサービス間でやり取りされるリソース表現には、通常は標準的なテキストベース形式が使用されます。
公開 API や外部 API では JSON が事実上の標準となっています。
一方、内部サービス間通信などで特にパフォーマンスが重要な場合には、gRPC が選択されることもあります。
HTTP
クライアントは HTTP リクエストを使用して HTTP サービスにアクセスします。
HTTP リクエストは、次の3つの要素で構成されます。
- リクエスト行:さらに次の3つの要素に分かれます
- HTTP動詞
- リクエストされたURI
- プロトコルのバージョン
- ヘッダー変数:Key-Value ペアで構成されます。標準ヘッダーに加え、必要に応じてカスタムヘッダーを追加できます
- リクエスト本文:サーバーに送信されるデータを含みます。主に POST や PUT など、データ送信を伴うリクエストで使用されます
HTTP メソッドは、リソースに対して実行する操作をサーバーに指示します。
HTTP 仕様では複数のメソッドが定義されていますが、REST API では主に次の4つが使用されます。
- GET:リソースを取得するために使用します
- POST:新しいリソースを作成するために使用します。サービスはリソースを作成し、通常は生成された一意の ID をレスポンスとして返します
- PUT:既存のリソースを更新、または指定された URI にリソースを作成するために使用します
- DELETE:リソースを削除するために使用します
HTTP サービスは、HTTP 仕様で定義された形式でレスポンスを返します。HTTP レスポンスも、次の3つの要素で構成されます。
- レスポンス行:HTTP バージョンとステータスコードが含まれます。200 番台は正常終了、400 番台はクライアント側のエラー、500 番台はサーバー側のエラーを表します
- ヘッダー変数:Key-Value ペアの集合です。たとえば Content-Type ヘッダーは、レスポンス本文の形式を示します
- レスポンス本文:リクエストされたリソースの表現が含まれ、JSON、XML、HTML などの形式で返されます
API
Google Cloud API
Google は API 設計に関するガイドラインを公開しており、命名規則、エラー処理、ドキュメント、バージョニング、互換性などについて推奨事項を示しています。
各 Google Cloud サービスは REST API を公開しています。
API メソッドは service.collection.verb という形式で定義されます。
- service:サービスのエンドポイント
- collection:instances、instanceGroups、instanceTemplates などのリソース集合
- verb:LIST、GET、INSERT などの操作
パラメータは URL クエリ、または JSON 形式のリクエスト本文として渡されます。
OpenAPI
OpenAPI は、API を外部に公開するための業界標準仕様です。
仕様のバージョン 2.0 は Swagger と呼ばれていました。
Swagger は OpenAPI を中心に構築された一連のオープンソースツール群であり、API の設計、構築、利用、ドキュメント化を支援します。
OpenAPI は API ファーストのアプローチを支援します。
OpenAPI を用いて API を設計することで、信頼できる単一の仕様を基点として、クライアントライブラリ、サーバースタブ、API ドキュメントを自動生成できます。
OpenAPI は Cloud Endpoints や Apigee でサポートされています。
gRPC
gRPC は Google によって開発された通信フレームワークで、マイクロサービス間の内部通信に適しています。
多数のプログラミング言語をサポートし、Protocol Buffers によって定義されたコントラクトを用いることで疎結合な設計を実現します。
バイナリ形式を採用しているため、通信効率とパフォーマンスに優れています。
HTTP/2 をベースとし、クライアントおよびサーバー双方のストリーミング通信をサポートします。
API管理ツール
Google Cloud における API 管理ツールには、Cloud Endpoints、Apigee、API Gateway があります。
Cloud Endpoints は API 管理ゲートウェイとして、Google Cloud 上のさまざまなバックエンドに対する API の開発、デプロイ、管理を支援します。
Apigee はエンタープライズ向けの API 管理プラットフォームで、クラウド、オンプレミス、ハイブリッド環境に対応しています。
API ゲートウェイ機能に加え、開発者ポータル、収益化、API 分析などの機能を備えています。バックエンドは、実行環境を問わず HTTP/HTTPS であれば利用可能です。
API Gateway は、バックエンド実装の詳細に依存せず、明確に定義された REST API を通じて、バックエンドサービスへ安全にアクセスするための仕組みを提供します。
これら3つのソリューションはいずれも、ユーザー認証、モニタリング、保護といった API 向けの共通機能に加え、OpenAPI や gRPC を扱うための機能を提供しています。
最後に
今回は、Google Cloud におけるマイクロサービスの設計方法とアーキテクチャについて整理しました。
次回は、Google Cloud でシステム設計を行う際に重要となる指標について、もう少し踏み込んでまとめていく予定です。
引き続き読んでいただけると嬉しいです。
以前の投稿
【Google Cloud入門】クラウドサービスの特徴とGoogle Cloudの触り方
【Google Cloud入門】リソースマネージメント
【Google Cloud入門】アクセス管理の基本 - IAM
【Google Cloud入門】サービスアカウントとCloud Identity
【Google Cloud入門】Compute Engineの基礎
【Google Cloud入門】コンピューティングオプションとマネージドインスタンスグループ
【Google Cloud入門】GKE入門の前準備-コンテナの基礎
【Google Cloud入門】GKE入門の前準備-Kubernetesの基礎
【Google Cloud入門】GKE入門の前準備-Kubernetesの構成
【Google Cloud入門】Googleのコンテナ仮想環境ーGoogle Kubernetes Engine
【Google Cloud入門】GCEとGKE以外のコンピューティングサービス
【Google Cloud入門】Google Cloudネットワークの基礎
【Google Cloud入門】Google Cloudネットワークへの接続とVPCの共有
【Google Cloud入門】Google Cloudネットワークの負荷分散
【Google Cloud入門】オブジェクトストレージサービスーCloud Storage
【Google Cloud入門】Google Cloudの構造化データストレージサービス
【Google Cloud入門】Google Cloudのストレージサービスの選び方
【Google Cloud入門】ストレージに関連する様々なサポートサービス
【Google Cloud入門】Google Cloud のプロンプトエンジニアリング
【Google Cloud入門】Google Cloud のオペレーションスイート
【Google Cloud入門】Google Cloud の DevOps 自動化
【Google Cloud入門】サービスの定義