今日学んだこと#
マイクロサービスアーキテクチャの基礎概念から運用パターンまでを体系的に整理しました。 特に、試験や実務で混同しやすいポイント(SAGAと2PC、ブローカー有無、オーケストレーションとコレオグラフィなど)を重点的にまとめています。
学習内容#
このメモの構成#
マイクロサービスアーキテクチャを理解するために、以下の流れで概念を整理します。
- 基礎概念:マイクロサービスとは何か、従来のアーキテクチャとの違い
- 実行基盤:サービスを動かすコンテナ技術とそのパターン
- 通信:分離されたサービス同士がどう連携するか
- 管理:多数のサービスをどう発見・管理するか
- データ:サービスごとに分かれたデータの整合性をどう保つか
- 運用:障害対策、監視、デプロイの自動化
1. 基礎概念・アーキテクチャ比較#
マイクロサービスとは#
独立してデプロイ可能で、ビジネスドメインに基づいてモデル化されたサービスの集合体で構成されるアーキテクチャ
ポイント1:独立デプロイ可能性
- 他のサービスを変更せずに、単独でデプロイできる
- 変更のリスクが局所化され、リリース頻度を上げられる
- 実現のためには疎結合が必須(サービス間の依存を最小限に)
ポイント2: ビジネスドメインに基づくモデル化
技術的な境界ではなく、ビジネスの境界でサービスを分割 マイクロサービスで最も難しいのは「サービス境界をどこに引くか」。 ここで**DDD(ドメイン駆動設計)**の考え方がガイドとして使われます。
DDDとは: 業務(ビジネス)の理解を中心においてソフトウェアを設計・実装する考え方。 「機能単位」ではなく「業務の概念単位」でモデルを作ります。
その他の特徴
- サービスごとに異なる技術スタック(言語・フレームワーク)を選択可能
- サービス間はAPI(REST、gRPC等)やメッセージングで通信
- 各サービスが自身の状態(データ)をカプセル化
モノリシック vs マイクロサービス#
モノリシックアーキテクチャとは、アプリケーション全体を単一のデプロイ単位として構築するアーキテクチャ。 すべての機能が1つのコードベースに含まれ、まとめてビルド・デプロイされます。
| 観点 | モノリシック | マイクロサービス |
|---|---|---|
| デプロイ単位 | アプリ全体 | サービス単位 |
| スケーリング | アプリ全体をスケール | サービスごとにスケール可能 |
| 障害影響 | 全体に波及しやすい | 障害を局所化できる |
| 開発速度 | 初期は速い | 初期は遅いが長期的に有利 |
ポイント: MSAのメリットは「サービスごとにスケーリングできるため、リソースの無駄がなくなりスケーリング速度が上がる」。レスポンスタイム向上やデータ管理が容易になるわけではありません。
SOA vs マイクロサービス#
SOA(サービス指向アーキテクチャ)とは、ビジネス機能をサービスとして分離し、それらを組み合わせてシステムを構築するアーキテクチャ。マイクロサービスの前身とも言える考え方ですが、いくつかの違いがあります。
注: 『マイクロサービスアーキテクチャ 第2版』では、マイクロサービスアーキテクチャはSOAの一種(SOAへの特定のアプローチ)として位置づけられています。本メモでは便宜上、両者を別のアーキテクチャとして比較します。
| 観点 | SOA | マイクロサービス |
|---|---|---|
| データベース | 共有データベース | サービスごとに専用DB |
| 通信 | ESB(重量級) | 軽量プロトコル(REST、gRPC) |
| サービス粒度 | 比較的大きい | 小さい |
ESB(Enterprise Service Bus)とは: サービス間の通信を仲介する中央集権的なミドルウェア。メッセージのルーティング、プロトコル変換、データ変換などを一手に担う。機能が豊富な反面、複雑化・肥大化しやすく、単一障害点になりやすいという課題がある。
2. コンテナ技術#
マイクロサービスの基本概念を理解したところで、次は「サービスをどう動かすか」という実行基盤の話に移ります。
マイクロサービスは複数の小さなサービスで構成されるため、各サービスをコンテナとしてパッケージングし、複数のコンテナを効率的に管理・運用する仕組みが必要になります。
- Docker Compose: 開発環境や小規模環境向けのコンテナ管理ツール
- Kubernetes: 本番環境や大規模環境向けのコンテナオーケストレーション基盤
Docker Compose#
複数のコンテナから成るサービスを構築・実行する手順を自動化する機能です。
できること:
- 複数コンテナの一括管理(起動・停止・削除)
- パッケージなどの依存をカプセル化
- 単一ホストでの実行
できないこと:
- セルフヒーリング(自動復旧)
- マルチホスト(複数マシン間)での管理
- オートスケール
ポイント:
- 「開発環境専用」ではない(本番でも使える)
- 起動・停止・削除はまとめて操作可能(個別操作のみではない)
Kubernetes#
コンテナオーケストレーションプラットフォームです。
基本用語:
- Node: Kubernetesクラスタを構成する物理/仮想マシン(サーバー)
- Pod: コンテナの実行単位。1つ以上のコンテナをまとめたもので、Node上で動作する
クラスタ
├── Node(マシン1)
│ ├── Pod(コンテナA)
│ └── Pod(コンテナB)
└── Node(マシン2)
└── Pod(コンテナC)
主な機能:
- セルフヒーリング: Pod障害時に指定数を満たすよう自動でPodを起動
- マルチノード管理
- オートスケール
- ローリングアップデート
ポイント:
- セルフヒーリングはPod単位(Node単位ではない)
- Nodeに障害が発生しても、別NodeでPodを再起動する(Nodeは作成しない)
kubectl setで変更した設定が自動で戻る機能はない
Docker Compose vs Kubernetes#
| 機能 | Docker Compose | Kubernetes |
|---|---|---|
| 複数コンテナ管理 | ○ | ○ |
| 依存カプセル化 | ○ | ○ |
| セルフヒーリング | × | ○ |
| マルチホスト | × | ○ |
| オートスケール | × | ○ |
3. コンテナパターン#
コンテナ技術の基礎を押さえたところで、コンテナを効果的に構成するためのデザインパターンを見ていきます。 これらのパターンは、サービスに機能を追加したり外部システムと連携したりする際の設計指針となります。
サイドカーパターン#
メインコンテナに補助的な機能を追加するコンテナを同じPodに配置します。
具体例:
- ログ転送コンテナ(メインアプリ + Fluentd)
- 監視エージェント(メインアプリ + Prometheus exporter)
特徴: メインの機能を拡張・補助する
アンバサダーパターン#
メインコンテナが外部システムと接続する際の中継を行うコンテナです。
具体例:
- DB接続先の抽象化(開発/本番で接続先が異なる場合でも、メインコンテナからは同じアドレスを参照)
- 外部APIへのプロキシ
特徴: 外部接続を中継し、疎結合を実現
アダプターパターン#
外部からのリクエストに対してデータフォーマットを変換するコンテナです。
具体例:
- 監視ソフトウェア用にメトリクスを整形
- レガシーシステムとの連携でデータ形式を変換
特徴: データのフォーマット変換
4. サービス間通信#
サービスが独立したコンテナとして動作するようになったら、次に考えるべきは「サービス同士がどうやって連携するか」という通信の問題です。ここではプロトコルの選択やメッセージングの方式について整理します。
同期 vs 非同期#
| 方式 | 特徴 | ユースケース |
|---|---|---|
| 同期 | レスポンスを待つ、即時性 | ユーザーへの即時応答が必要 |
| 非同期 | レスポンスを待たない、疎結合 | バックグラウンド処理、イベント駆動 |
REST#
REpresentational State Transferの略。HTTPメソッド(GET、POST、PUT、DELETE等)を使ってリソースを操作するAPIの設計スタイル。WebAPIの事実上の標準として広く普及しています。
gRPC#
Googleが開発した高性能なRPC(Remote Procedure Call)フレームワーク。リモートのサービスをあたかもローカルの関数のように呼び出せる仕組みを提供します。
特徴:
- HTTP/2による高速通信(多重化、ヘッダ圧縮)
- Protocol Bufferによるバイナリシリアライズ(JSONより軽量・高速)
- 双方向ストリーミング対応
- 多言語対応(クライアント/サーバーを異なる言語で実装可能)
REST vs gRPC#
| 観点 | REST | gRPC |
|---|---|---|
| プロトコル | HTTP/1.x or HTTP/2 | HTTP/2 |
| データ形式 | JSON(テキスト) | Protocol Buffer(バイナリ) |
| 用途 | 外部公開API | 内部サービス間通信(高速) |
| ブラウザ対応 | ○ | △(要プロキシ) |
補足: RESTはHTTPのバージョンに依存しない設計スタイルのため、HTTP/2上でも動作します。一方、gRPCはHTTP/2の機能(多重化、ストリーミング等)を前提としているため、HTTP/1とのネイティブな互換性はありません(gRPC-Webを使えば制限付きで動作可能)。
Protocol Buffer#
gRPCで使用されるIDL(Interface Definition Language:サービス間のインターフェースを言語に依存しない形式で定義するための言語)。データ構造やAPIの仕様を.protoファイルに記述し、各言語用のコードを自動生成します。
重要な特徴:
- フィールドは番号で管理
- 更新時は新しい番号を割り当て
- 古いフィールドの番号はreservedで残す(再利用禁止)
- 言語非依存だが、全言語対応ではなく主要言語でスタブ生成可能
ポイント: フィールド番号の管理とreservedが重要。
よくある誤解:
- × 全てのプログラミング言語でスタブ生成可能(主要言語のみ)
- × HTTP/1とネイティブに互換性あり(HTTP/2専用。gRPC-Web経由なら制限付きで動作可能)
ブローカーメッセージング#
メッセージブローカー(Kafka、RabbitMQ等)を介した通信です。
メッセージブローカーとは: 送信側と受信側の間に立ち、メッセージの受け渡しを仲介するミドルウェア。送信側はブローカーにメッセージを送るだけでよく、受信側の存在を知る必要がない。メッセージの一時保管(キュー)、複数の受信者への配信、配信保証などの機能を提供する。
特徴:
- バッファリング可能(一時的な負荷を吸収)
- 疎結合(送信側と受信側が直接知らない)
- 配信保証が容易
- 可用性が高い
ブローカーレスメッセージング#
メッセージブローカーを介さない直接通信(ZeroMQ等)です。
特徴:
- 低レイテンシ(ブローカー経由しない)
- 単一障害点がない(ブローカーがないため)
- 配信保証が難しい
- 密結合(サービスを直接参照)
ポイント: ブローカーレスは「疎結合」ではなく**「密結合」**。直接参照するためです。
よくある誤解:
- × 疎結合を保てる(直接参照するため密結合)
- × バッファリング可能(できない、それはブローカー有り)
ブローカー有 vs ブローカーレス#
| 観点 | ブローカー有 | ブローカーレス |
|---|---|---|
| 結合度 | 疎結合 | 密結合 |
| レイテンシ | 高め | 低い |
| 単一障害点 | あり(ブローカー) | なし |
| 配信保証 | 容易 | 難しい |
| バッファリング | 可能 | 不可 |
5. サービス管理・発見#
サービス間通信の方法が決まったら、次は「多数のサービスをどう管理し、お互いをどう見つけるか」という問題に対処する必要があります。サービス数が増えると、手動での管理は現実的ではなくなります。
API Gateway#
クライアントからのリクエストを受け、適切なサービスにルーティングします。
機能:
- ルーティング
- 認証・認可の一元化
- レート制限
- リクエスト/レスポンス変換
サービスディスカバリ#
動的に変化するサービスの場所(IP/ポート)を発見する仕組みです。
仕組み:
- サービスが起動時にサービスレジストリに登録
- クライアントがサービスレジストリから送信先を選択
ポイント:
- サービスディスカバリは「発見」。負荷分散ではない
- IPアドレスを静的に設定するのではなく、動的に発見する
- DockerやKubernetesなどのプラットフォームでもサポートされている
よくある誤解:
- × IPアドレスを静的に設定する(動的に発見する)
- × アプリケーション側で必ずAPIコールが必要(プラットフォームでサポート)
サービスレジストリ#
サービスのIP/ポート情報を保持するデータベースです。
代表例: Consul, etcd, ZooKeeper
サービスメッシュ#
サービス間通信を管理するインフラストラクチャ層です。
特徴:
- サービスの外側(サイドカープロキシ)で実装
- サービスコードを変更せずに機能追加
- 内側から外側へのリクエストにも利用可能
提供機能:
- サービスディスカバリ
- 分散トレーシング
- サーキットブレーカー
- mTLS(相互TLS認証:クライアントとサーバーが互いに証明書を検証し合う認証方式。サービス間の通信を暗号化し、なりすましを防ぐ)
代表例: Istio, Linkerd
ポイント:
- サービスの**「外側」**で実装(内側ではない)
- サーキットブレーカー「のみ」ではない(多機能)
よくある誤解:
- × サービスの内側で実装(外側、サイドカープロキシ)
- × サーキットブレーカーのみ(サービスディスカバリ、分散トレーシング等も含む)
- × 外から内へのリクエストのみ(内から外へも利用可能)
BFF(Backend for Frontend)#
クライアントの種類ごとにAPIゲートウェイを作成するパターンです。
具体例:
- Webアプリ用BFF
- モバイルアプリ用BFF
- IoTデバイス用BFF
メリット: クライアント固有のデータ加工処理を分離し、バックエンドとフロントエンドの複雑な処理を緩和
ポイント: BFFは「マイクロサービスごと」ではなく「クライアントごと」。
6. データ管理・トランザクション#
サービスの発見・管理の仕組みを整えたら、次は最も難しい課題の一つ「データ」に向き合います。マイクロサービスでは各サービスが専用のデータベースを持つため、サービス間でデータ整合性をどう保つかが重要なテーマとなります。
トランザクションとは: 「全部成功するか、全部失敗するか」のどちらかを保証するデータ操作の単位。例えば銀行振込では「送金元の残高減少」と「送金先の残高増加」が必ずセットで成功/失敗する必要があります。
Database per Service#
各サービスが専用のデータベースを持つパターンです。
メリット: サービス間の独立性、スキーマ変更の自由 デメリット: サービス間のデータ整合性が複雑
SAGAパターン#
各サービスのローカルトランザクションを非同期メッセージで繋げることで整合性を取るワークフローパターンです。
特徴:
- 分散トランザクション(2PC)を使わない
- 失敗時は補償トランザクションで取り消し
補償トランザクションとは: すでにコミットされた処理を「論理的に取り消す」ための逆操作。例えば「在庫を減らす」処理が完了した後に後続処理が失敗した場合、「在庫を戻す」という補償トランザクションを実行して整合性を回復する。物理的なロールバックではなく、新たな処理として実行される点が特徴。
ポイント: SAGAは「分散トランザクション」ではない。ローカルTx + 非同期メッセージ。
よくある誤解:
- × 分散トランザクションを使う(使わない、それは2PC)
- × コーディネータがロックする(ロックしない)
オーケストレーション型#
**中央のコントローラー(オーケストレーター)**がトランザクションを管理します。
特徴:
- 指揮者のように各サービスに指示
- ワークフローが明確
- 補償トランザクションを使った障害復旧機能を持つ
- 単一障害点になる懸念あり
コレオグラフィ型#
各サービスがイベントを発火し、他サービスがそれに反応します。
特徴:
- 自律分散(指揮者なし)
- 単一障害点がない
- ワークフローが追いにくい
オーケストレーション vs コレオグラフィ#
| 観点 | オーケストレーション | コレオグラフィ |
|---|---|---|
| 制御方式 | 中央集権的 | 自律分散 |
| 単一障害点 | あり | なし |
| ワークフロー | 明確 | 追いにくい |
| 障害復旧 | 補償トランザクションで対応 | 各サービスで対応 |
よくある誤解:
- × オーケストレーションは単一障害点がない(ある)
- × コレオグラフィは中央制御(自律分散)
2PC(Two-Phase Commit / 分散トランザクション)#
コーディネータが複数サービスのトランザクションを同期的に管理します。
フェーズ:
- Prepare: 各サービスにコミット可能か確認、ロック
- Commit/Rollback: 全サービスがOKならコミット、NGならロールバック
ポイント: 2PCは「同期」「ロック」。SAGAは「非同期」「ロックなし」。
イベントソーシング#
現在の状態ではなく、状態変更のイベント(履歴)を保存するパターンです。
特徴:
- データが更新されるたびにイベントがパブリッシュされる
- 監査ログが自動的に残る
- 任意の時点の状態を再現可能
- 同じイベントが複数回発火する可能性があるため、冪等なロジックが必要
ポイント: イベントは「必ず1度だけ」ではない。冪等性が必須。
よくある誤解:
- × イベントは必ず1度だけ届く(複数回届く可能性あり)
7. クエリパターン#
データ管理の基本が分かったところで、「複数サービスにまたがるデータをどう取得するか」というクエリの問題を扱います。サービスごとにDBが分かれているため、従来のJOINは使えません。
CQRS(Command Query Responsibility Segregation)#
書き込み(Command)と読み取り(Query)でモデルを分離するパターンです。
特徴:
- 複雑なクエリにも対応可能
- 読み取り側を最適化できる
- 結果整合性になる(書き込みと読み取りの同期にタイムラグ)
- 設計が複雑
ポイント: CQRSは「読み書き分離」→「結果整合性」。リアルタイムではない。
よくある誤解:
- × リアルタイムにデータ取得可能(結果整合性のためタイムラグあり)
- × APIコンポジションより効率的にリアルタイム取得(逆)
APIコンポジションパターン#
複数サービスを呼び出し、メモリ内でデータを結合してクエリを実現します。
特徴:
- シンプルな実装
- オーバーヘッドが大きい(複数サービス呼び出し)
- 非効率なメモリ内結合
- リアルタイムにデータ取得可能
ポイント: APIコンポジションは「シンプル」だが「オーバーヘッド大」「メモリ内結合」。
CQRS vs APIコンポジション#
| 観点 | CQRS | APIコンポジション |
|---|---|---|
| 設計 | 複雑 | シンプル |
| パフォーマンス | 読み取り最適化可能 | オーバーヘッド大 |
| 整合性 | 結果整合性 | リアルタイム可能 |
| 用途 | 複雑なクエリ | シンプルな結合 |
8. 耐障害性・可観測性#
ここまでで設計と実装の話が一段落しました。ここからは運用面の話に入ります。分散システムでは障害は避けられません。障害発生時の影響を最小化する仕組みと、問題を素早く検知するための可観測性が重要になります。
サーキットブレーカー#
エラーレートが閾値を超えた場合、それ以降のリクエストを即エラーとして返すパターンです。
3つの状態:
- Closed: 正常。リクエストを通す
- Open: 障害検知。リクエストを即エラーで返す
- Half-Open: 試験的にリクエストを通し、成功すればClosedへ
ポイント:
- 「キューに入れて後で処理」ではない → 即エラー
- 「秒間リクエスト数の上限」ではない → エラーレートの閾値
分散トレーシング#
一意のID(Trace ID)をリクエストに付与し、サービス間を伝播させることでリクエストの流れを追跡します。
構成要素:
- Trace: 1つのリクエスト全体
- Span: 各サービスでの処理単位
代表ツール: Jaeger, Zipkin
ポイント: 個々のリクエストに一意のIDを付与し伝播させるのが特徴。
その他の可観測性パターン#
| パターン | 役割 |
|---|---|
| 分散トレーシング | リクエストの流れを追跡(ID伝播) |
| エクセプショントラッキング | 例外・エラーの追跡 |
| アプリケーションメトリクス | CPU、メモリ、レイテンシ等の数値監視 |
| ログ集約 | 複数サービスのログを一元管理 |
9. デプロイ・CI/CD#
障害対策と監視の仕組みが整ったら、最後はデプロイの自動化です。マイクロサービスはサービス数が多いため、手動デプロイは現実的ではありません。CI/CDパイプラインとデプロイ戦略が運用の要となります。
CI/CD#
CI(Continuous Integration): コードの統合・ビルド・テストを自動化 CD(Continuous Delivery/Deployment): デプロイを自動化
メリット:
- ヒューマンエラーの回避
- 工数削減
- 迅速なフィードバック
ポイント:
- 「コード記述量を減らす」ではない
- 「インフラ構成管理で冪等性を担保」ではない(それはIaC)
デプロイ戦略#
| 戦略 | 特徴 |
|---|---|
| カナリアデプロイ | 一部のユーザーにのみ新バージョンをリリース |
| ブルーグリーンデプロイ | 2つの同一環境を切り替え、瞬時のロールバック可能 |
| ローリングデプロイ | インスタンスを順次置き換え |
まとめ#
最後に、全概念を一覧表で総復習します。「正しい理解」と「よくある誤解」を対比させることで、試験や実務でのミスを防ぎます。
| 概念 | 正しい理解 | よくある誤解 |
|---|---|---|
| セルフヒーリング | Pod数を維持するよう自動起動 | Node作成 × |
| Docker Compose | 起動・停止・削除をまとめて操作可能 | 個別操作のみ × |
| サイドカー | 補助機能を追加 | 中継 ×、変換 × |
| アンバサダー | 外部接続を中継 | 補助 ×、変換 × |
| アダプター | データを変換・整形 | 補助 ×、中継 × |
| gRPC | HTTP/2、フィールド番号管理 | HTTP/1互換 × |
| サーキットブレーカー | エラーレート閾値で即エラー | キュー待機 ×、秒間リクエスト上限 × |
| サーガ | ローカルTx + 非同期メッセージ | 分散トランザクション × |
| オーケストレーション | 中央集権、単一障害点あり | 単一障害点なし × |
| コレオグラフィ | 自律分散、単一障害点なし | 中央制御 × |
| CQRS | 読み書き分離、結果整合性 | リアルタイム × |
| APIコンポジション | シンプル、オーバーヘッド大 | 効率的 × |
| ブローカーレス | 密結合、低レイテンシ | 疎結合 × |
| サービスディスカバリ | レジストリから動的に選択 | 静的IP設定 × |
| サービスメッシュ | サービスの外側で実装、多機能 | 内側 ×、サーキットブレーカーのみ × |
| BFF | クライアント別にゲートウェイ | サービス別 × |
| イベントソーシング | 冪等なロジックが必要 | 1度だけ届く × |
| CI/CD | ヒューマンエラー回避、工数削減 | コード記述量削減 ×、インフラ構成管理 × |
| SOA vs MSA | SOAは共有DB、MSAは専用DB | 逆 × |
参考資料#
- マイクロサービスアーキテクチャ 第2版
- 著者:Sam Newman
- 監訳:佐藤直生
- 訳者:木下哲也
- 出版社:オライリージャパン
- 出版年:2022年