マイクロサービスは、business capability(業務上の能力)ごとに分けたserviceを、独立して変更・deploy・運用できるようにするarchitecture styleです。
「codeを小さなAPIへ分けること」だけが目的ではありません。network越しの失敗、dataの結果整合性、複数deploy、監視、security、契約version管理というcostを引き受けて、teamとserviceの自律性を得る選択です。

Monolith・modular monolith・microservices
| 観点 | Monolith / modular monolith | Microservices |
|---|---|---|
| process・deploy | 基本は一つの単位 | serviceごとに独立可能 |
| module間通信 | process内の呼び出し | network・message broker経由 |
| transaction | 一つのDB transactionに収めやすい | serviceをまたぐ整合性設計が必要 |
| 変更の調整 | 一つのrepository・releaseで調整しやすい | contract互換性とdeploy順序を管理 |
| 障害 | process内で影響し得る | network failureが増え、分離には設計が必要 |
| 運用 | build・deploy・監視対象が少ない | service数に応じて運用対象が増える |
modular monolithは、一つのdeploy単位の中でmoduleの公開interfaceとdata ownershipを分けます。module境界が明確なら、networkを増やさずdomainを学び、必要になった境界だけを後からserviceとして抽出できます。
Monolithでもmodule分離、複数言語との連携、部分的なscaleは可能です。Microservicesでも共有library、platform、組織上の承認に強く依存すれば独立性は得られません。名前ではなく、必要な変更独立性と実際のcouplingを比較します。
採用前に答える質問
次の問いに具体的な根拠があるか確認します。
- 一部の機能を、他の機能と別の頻度でdeployする必要があるか
- 独立してscaleしたい負荷や、異なる可用性・規制要件があるか
- 一つのbusiness capabilityをend-to-endで所有できるteamがあるか
- domainとtransactionの境界を説明できるか
- CI/CD、observability、on-call、security updateをserviceごとに維持できるか
- network failureと結果整合性をproduct要件として扱えるか
- contract testと後方互換な変更手順を運用できるか
「teamが何人以上」「利用者が何万人以上」という固定値では決まりません。小さなteamでも強い分離要件がある場合はあり、大きなsystemでも境界が不明なら分割が変更を遅くします。
判断: 独立deployの必要性より分散systemのcostが大きい間は、modular monolithを保つのが妥当です。Microservicesを採用しないこともarchitecture上の選択です。
service境界はclassの数ではなく業務で決める
service境界の候補は、bounded contextやbusiness capabilityから探します。たとえば「注文」は単なるOrder classではなく、注文受付、価格確定、状態遷移、取消規則などのmodelとinvariant(常に守る条件)を持ちます。
境界を検討するときは次を並べます。
- 同じ言葉が同じ意味を持つ範囲
- 一つのtransactionで必ず守るinvariant
- 一緒に変更されるruleとdata
- 業務上のownerと運用責任
- 外部へ公開するcommand・query・event
- 障害時に止めてよい範囲と復旧順序
小さく分けるほど良いわけではありません。毎回複数serviceを同期呼び出ししないと一つの操作が終わらないなら、境界が細かすぎるか、data ownershipが曖昧な可能性があります。
data ownership
原則として、serviceは自分が所有するdataを自分のinterface越しに変更します。他serviceがtableへ直接書くと、schema変更、認可、invariant、deployが再び結合します。
「database per service」は、必ずserviceごとに別のDB製品やserverを用意するという意味ではありません。少なくともschemaとwrite ownershipを分け、他serviceが内部tableを契約として使わないようにします。
一方、serviceをまたぐ一つのACID transactionは難しくなります。どの整合性を即時に守り、どれを結果整合性にできるかを業務側と決めます。reportや検索画面では、API composition、read model、eventによる複製などの選択肢があります。
同期通信と非同期通信
| 方式 | 向く要求 | 主なcost |
|---|---|---|
| HTTP / gRPCなどの同期呼び出し | 呼び出し中に答えが必要 | timeout、連鎖障害、latency、version互換 |
| message / eventによる非同期処理 | 時間をずらせる、consumerを分離したい | 重複、順序、遅延、再処理、結果整合性 |
同期か非同期かを「新しいから」「高速だから」で決めません。利用者へいつ結果を返すか、失敗を誰が再処理するか、重複しても安全か、順序が必要かを先に決めます。
API GatewayやBFFは入口のrouting、認証、rate limit、client別集約などに使えますが、すべてのsystemに必須ではありません。業務ruleをgatewayへ集めると新しいmonolithになるため、責務を限定します。
危険な簡易実装を避ける
分散systemのpatternは、短いsample codeだけでは失敗時の状態を表せません。次の問題はoverview記事で自作実装せず、専用の設計として扱います。
DB更新とevent発行のdual-write
「DBへ注文をcommitした後にeventをpublishする」実装は、その間にprocessが停止すると、注文だけが保存されeventが失われます。先にpublishすれば、DBのrollback後に存在しない注文のeventが届く場合があります。
同じlocal transactionにoutbox recordを保存して後で配送するTransactional Outbox、CDCなどを検討します。それでもmessageの重複、順序、配送停止、poison message、監視と再処理が必要です。
retry
全例外を同じ回数retryすると、認可失敗やvalidation errorまで繰り返し、障害中の依存先へ負荷を増やします。timeout、retry可能な一時障害、回数、backoffとjitter、全体deadline、retry budgetを決めます。
複数の層がそれぞれretryすると試行回数が掛け算になります。副作用を持つ処理は、同じidempotency keyと結果の再利用など、重複実行を防ぐ契約なしにretryしません。
circuit breaker
単純なfailureCountと3状態だけでは、並行request、時間窓、half-openの試行数、timeout、失敗分類、instanceごとの状態、fallbackの正しさを扱えません。
利用するHTTP client、service mesh、resilience libraryの実績ある機能を検討し、timeout・bounded retryとの順序と粒度をtestします。fallbackは「古くても正しいdata」など業務上許容できる場合だけ使い、errorを成功に見せません。
Saga
Sagaのcompensationは、database transactionのrollbackと同じではありません。すでに送ったemailや外部決済を完全に元へ戻せない場合があり、補償自体もtimeout・重複・失敗します。
stepと状態をdurableに保存し、commandを冪等にし、補償失敗のretry・alert・manual repairを設計します。単純なtry/catchで成功済み処理を逆順に呼ぶだけでは、process停止後に再開できません。
障害分離は自動ではない
serviceを別processへ分けても、依存先を同期で待ち続けたり、共有DB・共有queue・共通認証基盤へ集中したりすれば障害は連鎖します。
各依存にtimeoutとresource上限を設定し、queue・connection pool・threadなどを必要に応じて分離します。readiness checkが依存先障害ですべて失敗し、正常なinstanceまでload balancerから外れる構成にも注意します。
「一つのserviceが停止したとき利用者に何を返すか」「復旧後にどのdataを再処理するか」をfailure testで確認して、初めて分離の効果を評価できます。
observabilityとsecurityは導入条件
一つのrequestがserviceをまたぐため、共通のtrace context、service名、version、環境、request結果を関連付けます。ただしuser ID、token、Cookie、決済情報、request body全体をspanやlogへ安易に記録しません。
service間通信でも認証と認可が必要です。mTLSは接続するworkloadを確認する手段、access tokenは主体やscopeを伝える手段として役割が異なります。secret rotation、network policy、least privilege、dependency updateをservice数に応じて自動化します。
段階的に移行する
既存monolithを一度に分解すると、正しい境界を学ぶ前にdata移行と通信経路が増えます。
- monolith内でmoduleとownerを明確にする
- change couplingと運用上の問題を計測する
- 独立deployの価値が高い一つの境界を選ぶ
- contract、data移行、observability、rollbackを準備する
- 一部trafficから移し、障害と運用costを確認する
- 得られた知識で次の境界を見直す
Strangler Figなどの段階移行を使い、移行期間中のsource of truthと二重書き込みを明確にします。
採用判断のまとめ
Microservicesは、独立deploy・scale・ownershipが必要な境界に使います。採用前に次を確認します。
- business capabilityとtransaction境界を説明できる
- serviceごとのownerとon-call責任がある
- CI/CD、contract test、observability、security updateを自動化できる
- network failure、重複、遅延、結果整合性をproduct仕様として扱える
- dual-write、retry、Saga、breakerを短い自作codeで済ませない
- modular monolithより大きな価値を計測できる
関連記事
参考リソース
- Microsoft - Microservices architecture style
- Microsoft - Identify microservice boundaries
- Microsoft - Data considerations for microservices
- Microsoft - Design patterns for microservices
- AWS Builders’ Library - Timeouts, retries and backoff with jitter
- OpenTelemetry - Observability primer
- The Twelve-Factor App