Article

モノリシック vs マイクロサービス:アーキテクチャの違いと選定ポイント

高田晃太郎
モノリシック vs マイクロサービス:アーキテクチャの違いと選定ポイント

研究データでは、O’Reillyの2020年調査で企業の約77%が何らかの形でマイクロサービスを採用しているとされ、CNCFの最新サーベイでもコンテナ本番利用は一般化しています¹²。一方で、DORAの年次レポートが示す高パフォーマンス組織の特徴は「アーキテクチャの種類」ではなく「疎結合なデリバリー能力」で、デプロイ頻度や変更リードタイム(コード変更が本番反映されるまでの時間)の短縮が成果に強く相関します³。公開事例を俯瞰すると、設計思想としてのマイクロサービス化そのものが生産性を保証するわけではなく、組織とプラットフォーム運用の成熟度が伴わなければ逆効果になり得るという示唆が得られます。クラウド、Kubernetes、サービスメッシュといった要素技術が一般化した今だからこそ、モノリシックとマイクロサービスの選定は「思想」ではなく「制約に対する適合度」で決めるという原則に立ち返る必要があります²。

モノリシックとマイクロサービスの本質的な違い

両者の違いは表面的にはデプロイ単位や技術スタックの自由度に見えますが、根底にあるのは結合度と故障分離の設計です。モノリシックは単一プロセス内に主要機能がまとまり、アプリケーション内呼び出しが中心となるため、メモリ内の関数呼び出しが支配的です。Jeff Deanの著名なレイテンシの目安ではメモリアクセスがナノ秒〜数百ナノ秒オーダーであるのに対し、ネットワーク越しのRPC(遠隔手続き呼び出し)はシリアライズやTLSハンドシェイク、キューイングの影響を受け、同一データセンター内の往復でも数百マイクロ秒〜数ミリ秒オーダーの遅延が積み上がる可能性があります⁴。この差は高QPS・低レイテンシ要件で無視できません⁴。

他方、マイクロサービスはプロセス境界とチーム境界を一致させやすく、独立デプロイやスケール単位のきめ細かさを得られます。失敗時の影響範囲を狭められる一方で、分散システム特有の失敗モードと可観測性(メトリクス・ログ・トレースの観測)、整合性の問題が日常になる点を軽視すべきではありません。CAP定理(ネットワーク分断下で一貫性・可用性・分断耐性の三つを同時には満たせないという原理)の現実的な読み替えとして、ネットワーク分断や部分故障は避けられず、結果整合や補償トランザクション(分散環境での取り消しパターン)などのパターンを設計段階から織り込む必要があります⁵⁶。

実運用では、モジュラーモノリスのようにドメイン境界を明確に切りながら単一デプロイを維持するアプローチが有効です。ドメインの凝集度が高く、頻繁に連動変更が発生する領域は単体デプロイ寄りの方がトランザクション管理が単純で、変更速度も出しやすくなります。逆に、責務が安定しデータ境界が明確、利用パターンやスケール特性が異なるサブドメインは独立サービス化の候補になります。コンウェイの法則を踏まえると、チームトポロジーを先に設計し、チーム境界が安定している箇所にサービス境界を合わせるのが安全です。

レイテンシと信頼性のトレードオフ

サービスを細かく分割するとネットワーク呼び出しが増え、P99レイテンシ(遅い方から1%地点の遅延)が悪化しやすくなります。ヘッドオブラインブロッキングやN+1クエリの分散版とも言える現象が起きるため、バックプレッシャー、サーキットブレーカー、バルクヘッドを含むレジリエンス設計が不可欠です⁵。単体デプロイでも外部依存は存在しますが、プロセス内の制御が効く分、可観測性への要求は相対的に低く済みます。どちらが優れているかではなく、どの失敗モードをどのコストで引き受けるかが本質です。

選定のフレームワークと判断基準

判断は二軸のスコアリングで進めると現実的です。まずドメインの複雑性と変更頻度を横軸に置き、縦軸に組織・プラットフォームの成熟度を置きます。変更頻度が高く、かつチームが独立デプロイを回せるSRE体制(運用信頼性を担う組織)、CI/CD、IaC(Infrastructure as Code)、可観測性が整っているなら分割の選好が高まります。逆に、変更頻度が高いのにプラットフォーム成熟度が低い場合、分散運用の摩擦が開発速度を著しく下げます。この場合はモジュラーモノリスで疎結合な内部境界を育て、後方互換APIの規律や契約テストを導入し、将来の分割に備えるのが得策です。

データ整合性要件も重要です。強いトランザクション一貫性を単一境界で求める業務は、分散トランザクションの複雑さと運用コストを正当化しにくい傾向があります。イベント駆動で結果整合を許容できる領域や、監査要件がサービスごとの独立ストレージで満たせる領域は、サービス分割のリターンが見込みやすいといえます。リーガル・監査・データ主権の規制要件が強い場合は、データ境界に合わせてサービス境界を設計し、データ複製とマスクを前提にしたイベントスキーマ設計が鍵になります⁵⁶。

人と組織の観点では、フロー効率(価値の流れの速さ)とリソース効率(個々の稼働率)のどちらを重視するかを明確にします。リソース効率を優先し共通基盤に集約しすぎると、プラットフォームSPOFが生まれ開発のボトルネックになります。逆に各サービスが自由に技術選定すると、サポート対象が爆発しプラットフォーム税(統一と運用のための追加コスト)が上がります。解として、ゴールデンパスを用意し、認証・テレメトリ・デプロイ標準をテンプレートで提供しながら逸脱にも明確なコストを設定するのが現実的です。

チーム境界の設計はTeam Topologiesの要点解説、クラウドコストの見える化はKubernetesコスト最適化の基礎、ドメイン分割はDDD基礎と境界づけられたコンテキスト。

ケーススタディの要点

B2Cの成長プロダクトで、キャンペーン、レコメンド、注文管理が急速に複雑化したケースを考えます。まず注文管理と決済をモジュラーモノリスとして強固にまとめ、活動量の変動が大きいレコメンドとキャンペーンをイベント駆動の独立サービスとして切り出す。こうした段階的分割により、変更の独立性や並行開発のしやすさが高まり、リードタイム短縮やキャンペーン同時運用数の増加が期待できます。一方で可観測性の整備、SLO(サービスレベル目標)の定義、オンコール設計などに初期投資が必要になり、短期的にはプラットフォーム税が増える可能性があります。短期の摩擦を許容し、中期の学習曲線を越える意思決定が効果を左右します。

実装パターンと最小構成のコード例

アーキテクチャの議論を実装に落とすため、最小限のパターンをコードで具体化します。モノリシックでは内部モジュールの境界に依存逆転を用い、マイクロサービスでは契約駆動、回復性、観測可能性を標準化します。

モジュラーモノリス:層と境界の分離(Spring Boot)

// build.gradle
plugins {
  id 'java'
  id 'org.springframework.boot' version '3.2.5'
}
dependencies {
  implementation 'org.springframework.boot:spring-boot-starter-web'
}
// domain/OrderService.java
package com.example.domain;
public class OrderService {
  private final PaymentGateway gateway;
  public OrderService(PaymentGateway gateway){this.gateway = gateway;}
  public Order place(OrderRequest req){
    // ドメインロジック(集約内で完結)
    var order = Order.create(req);
    gateway.authorize(order.paymentInfo());
    return order;
  }
}
// web/OrderController.java
@RestController
@RequestMapping("/orders")
public class OrderController {
  private final OrderService service;
  public OrderController(OrderService service){this.service = service;}
  @PostMapping
  public ResponseEntity<Order> create(@RequestBody OrderRequest req){
    try { return ResponseEntity.ok(service.place(req)); }
    catch (PaymentException ex){ return ResponseEntity.status(402).build(); }
  }
}

単一デプロイでありつつ、webとdomainの依存方向を固定することで、API契約が変わらない限り内部変更の影響を局所化できます。

サービス間契約:gRPCのスキーマ駆動

// order.proto
syntax = "proto3";
package order.v1;
service OrderService {
  rpc Place (PlaceRequest) returns (PlaceResponse) {}
}
message PlaceRequest { string user_id = 1; repeated LineItem items = 2; }
message PlaceResponse { string order_id = 1; string status = 2; }
message LineItem { string sku = 1; int32 qty = 2; }

生成コードに依存し、後方互換を壊す変更(フィールド削除や型変更)をCIで阻止します。HTTP/JSONの場合もOpenAPIで同様に契約を固定します。

APIゲートウェイ:ルーティングと認可の統一(Kong例)

# kong.yaml (declarative config)
_format_version: "3.0"
services:
  - name: order
    url: http://order:8080
    routes:
      - name: order-r
        paths: ["/orders"]
plugins:
  - name: jwt
    config:
      key_claim_name: kid

入口で認証・レート制御を統一し、下流サービスは業務責務に集中します。

ローカル統合:docker-composeで最小構成

version: "3.9"
services:
  order:
    build: ./order
    environment:
      - DATABASE_URL=jdbc:postgresql://db/order
    depends_on: [db]
  campaign:
    build: ./campaign
  db:
    image: postgres:16
    environment:
      - POSTGRES_PASSWORD=postgres
    ports: ["5432:5432"]

ローカルで複数サービスを統合し、契約と回復性を開発段階から検証します。

回復性:Resilience4jのサーキットブレーカー

# application.yml
resilience4j:
  circuitbreaker:
    instances:
      payment:
        slidingWindowSize: 20
        failureRateThreshold: 50
        waitDurationInOpenState: 15s
// PaymentClient.java
try {
  return cb.executeSupplier(() -> http.post(uri, payload));
} catch (CallNotPermittedException e) {
  return PaymentResult.deferred(); // フォールバック
}

下流の遅延を早期に切り離し、上流のP99を守る発想が重要です⁵。

可観測性:OpenTelemetryでの分散トレース(Node.js)

import { NodeSDK } from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
const sdk = new NodeSDK({
  traceExporter: new OTLPTraceExporter({ url: process.env.OTLP_URL }),
  instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();

トレースIDをフロント〜バックエンド〜DBまで貫通させ、SLO違反の根因を迅速に特定します。

コスト、リスク、ROIを数字で捉える

意思決定を定量化するために、三つの観点で3年スパンの評価を行います。まずプラットフォーム運用コストです。Kubernetes、サービスメッシュ、ログ・トレース基盤、セキュリティスキャン、GitOpsを素直に積み上げると、追加のSRE/プラットフォーム運用リソースの継続確保が必要になりやすく、クラウドリソースにはワークロードに対するオーバーヘッドが発生します。小規模でトラフィックが安定している場合、この税は無視できません。

次にパフォーマンスとSLOの観点です。単体デプロイではスループット最大化が容易で、キャッシュやDB接続プールを一箇所で最適化できます。分割した構成ではネットワークホップごとの遅延(同一DCでも数百マイクロ秒〜数ミリ秒)が蓄積し⁴、下流のP99を守るための余剰キャパシティ確保が必須になります。これを逆手に取り、可観測性と自動スケールでコストの弾力性を得られる設計に振るかが鍵です。

最後にビジネス価値です。独立デプロイとチーム自律性が実現すれば、機能の並行開発とA/Bテストの速度が向上し、学習ループが締まるという恩恵が期待できます⁷。公開事例でも、分割の妥当性が高い領域での移行はリードタイム短縮や障害半径の縮小につながったと報告される一方、妥当性が低い領域では運用負債が増えてリードタイムが悪化する傾向が指摘されます。選定ミスの損失は選定成功の利益より大きくなりやすいという非対称性を前提に、慎重な適用範囲の見極めが重要です。

移行の現実的な道筋

段階的な抽象化を先に進め、公開API・イベント・データ所有権を整理した上で、トラフィックの小さい境界から切り出します。観測とロールバック戦略が整ったら、影響の小さい機能フラグでトラフィックを段階移行し、SLOを監視しながら閾値内で進めます。重要なのは、プラットフォームの出来に合わせて移行速度を調整することです。可観測性と自動化の成熟度が不十分な段階でサービスを増やしても、複雑性だけが増します。技術的負債は分割で消えるのではなく、分散されるという現実を忘れないでください⁵。

まとめ:選択の基準は“適合”であり“信仰”ではない

アーキテクチャは目的ではなく手段です。単体デプロイはシンプルさと一貫性で速度を作れますし、分割構成はチーム自律性と回復性でスケールする余白を作れます。いまの制約に最も適合する形を選び、将来の選択肢を最大化する設計をすることが経営と技術の橋渡しになります。もし迷っているなら、まずはモジュラーモノリスで境界を明確にし、契約と観測の規律を整えながら、切り出しやすい領域から小さく実験してみてください。その結果がチームに何をもたらしたかを測定し、次の一歩を決めれば良いのです。いまのプロダクトと組織に最適な一手は何か、そして12カ月後にどんな学習を手にしていたいか。次のスプリントの計画に、その問いをそっと差し込んでみませんか。

参考文献

  1. O’Reilly. Microservices Adoption in 2020: O’Reilly Survey Finds 77% Are Using Microservices. 2020. URL: https://www.oreilly.com/pub/pr/3307
  2. Cloud Native Computing Foundation (CNCF). CNCF Annual Survey 2023. 2023. URL: https://www.cncf.io/reports/cncf-annual-survey-2023/
  3. Google/DORA (DevOps Research & Assessment). Accelerate State of DevOps Report 2021. 2021. URL: https://dora.dev/research/2021/dora-report/
  4. Jon Bodner (compiling Jeff Dean’s data). Latency Numbers Every Programmer Should Know. URL: https://gist.github.com/jboner/2841832
  5. AWS Prescriptive Guidance. Decomposing monoliths. URL: https://docs.aws.amazon.com/prescriptive-guidance/latest/modernization-decomposing-monoliths/welcome.html
  6. Chris Richardson. Developing Sagas (Part 3). microservices.io. 2019. URL: https://microservices.io/post/sagas/2019/08/15/developing-sagas-part-3.html
  7. Atlassian. Microservices vs. Monolith. URL: https://www.atlassian.com/ja/microservices/microservices-architecture/microservices-vs-monolith