マイクロサービスとは - 採用判断とサービス境界

11分 で読める | 2025.12.02

公式ドキュメント

マイクロサービスは、business capability(業務上の能力)ごとに分けたserviceを、独立して変更・deploy・運用できるようにするarchitecture styleです。

「codeを小さなAPIへ分けること」だけが目的ではありません。network越しの失敗、dataの結果整合性、複数deploy、監視、security、契約version管理というcostを引き受けて、teamとserviceの自律性を得る選択です。

一つのDeploy単位であるMonolith、内部のModule境界を分けるModular Monolith、Serviceごとに独立DeployしDataを所有するMicroservicesを比較する図

Monolith・modular monolith・microservices

観点Monolith / modular monolithMicroservices
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を比較します。

採用前に答える質問

次の問いに具体的な根拠があるか確認します。

  1. 一部の機能を、他の機能と別の頻度でdeployする必要があるか
  2. 独立してscaleしたい負荷や、異なる可用性・規制要件があるか
  3. 一つのbusiness capabilityをend-to-endで所有できるteamがあるか
  4. domainとtransactionの境界を説明できるか
  5. CI/CD、observability、on-call、security updateをserviceごとに維持できるか
  6. network failureと結果整合性をproduct要件として扱えるか
  7. 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移行と通信経路が増えます。

  1. monolith内でmoduleとownerを明確にする
  2. change couplingと運用上の問題を計測する
  3. 独立deployの価値が高い一つの境界を選ぶ
  4. contract、data移行、observability、rollbackを準備する
  5. 一部trafficから移し、障害と運用costを確認する
  6. 得られた知識で次の境界を見直す

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より大きな価値を計測できる

関連記事

参考リソース

← 一覧に戻る
PR
PR
PR
PR