Skip to content
Published on

マイクロサービスアーキテクチャ2025完全ガイド:モノリスからMSA、そしてモジュラーモノリスへ

Authors

はじめに

2025年(ねん)、ソフトウェアアーキテクチャの状況(じょうきょう)が再(ふたた)び変(か)わりつつあります。2010年代(ねんだい)中盤(ちゅうばん)にNetflixとAmazonが主導(しゅどう)したマイクロサービスブーム以降(いこう)、多(おお)くの企業(きぎょう)がMSAを導入(どうにゅう)しましたが、その多(おお)くが「分散(ぶんさん)モノリス(Distributed Monolith)」という最悪(さいあく)の結果(けっか)に直面(ちょくめん)しました。

DHH(Ruby on Rails創設者(そうせつしゃ))の「Majestic Monolith」宣言(せんげん)、Amazon Prime Videoチームの MSAからモノリスへの回帰(かいき)、Segmentのマイクロサービス撤回(てっかい)— これらの事例(じれい)は業界(ぎょうかい)に強力(きょうりょく)なメッセージを送(おく)りました。アーキテクチャはチームの規模(きぼ)と問題(もんだい)の複雑度(ふくざつど)に合(あ)わせるべきだということです。

このガイドでは、モノリスからSOA、MSA、そして2025年(ねん)のトレンドであるモジュラーモノリスまで、アーキテクチャの全(ぜん)スペクトラムを扱(あつか)います。サービス分解戦略(せんりゃく)、通信(つうしん)パターン、Service Mesh、分散(ぶんさん)トランザクション、オブザーバビリティ、API Gateway、デプロイ戦略(せんりゃく)、マイグレーションパターン、アンチパターンまで — マイクロサービスに関(かん)する全(すべ)てを整理(せいり)します。


1. アーキテクチャの進化:モノリスからモジュラーモノリスまで

1.1 モノリシックアーキテクチャ

全(すべ)ての機能(きのう)が一(ひと)つのデプロイ単位(たんい)で構成(こうせい)されます。

+------------------------------------------+
|              Monolith                     |
|  +--------+ +--------+ +--------+        |
|  |  User  | | Order  | |Payment |        |
|  | Module | | Module | | Module |        |
|  +--------+ +--------+ +--------+        |
|  +----------------------------------+    |
|  |        Shared Database           |    |
|  +----------------------------------+    |
+------------------------------------------+

メリット:

  • 開発(かいはつ)/デバッグ/デプロイがシンプル
  • トランザクション管理(かんり)が容易(ようい)(ACID保証(ほしょう))
  • IDEで全(ぜん)コード探索(たんさく)可能(かのう)
  • ネットワーク遅延(ちえん)なし

デメリット:

  • コードベース肥大化(ひだいか)でビルド/デプロイ時間(じかん)増加(ぞうか)
  • 一(ひと)つのモジュール変更(へんこう)がシステム全体(ぜんたい)に影響(えいきょう)
  • 技術(ぎじゅつ)スタック変更(へんこう)が困難(こんなん)
  • チーム規模(きぼ)拡張(かくちょう)に限界(げんかい)

1.2 SOA(サービス指向アーキテクチャ)

2000年代(ねんだい)のエンタープライズ環境(かんきょう)で流行(りゅうこう)したアーキテクチャです。ESB(Enterprise Service Bus)を中心(ちゅうしん)にサービスを接続(せつぞく)します。

+--------+    +--------+    +--------+
| Service|    | Service|    | Service|
|   A    |    |   B    |    |   C    |
+---+----+    +---+----+    +---+----+
    |             |             |
+---v-------------v-------------v---+
|        Enterprise Service Bus     |
|    (SOAP, WSDL, XML, Routing)     |
+-----------------------------------+

SOAはサービス再利用(さいりよう)を強調(きょうちょう)しましたが、ESBが過度(かど)なロジックを担当(たんとう)し、「Smart Pipes, Dumb Endpoints」アンチパターンが発生(はっせい)しました。

1.3 マイクロサービスアーキテクチャ

Netflix、Amazon、Uberが主導(しゅどう)した現代的(げんだいてき)な分散(ぶんさん)アーキテクチャです。

+--------+     +--------+     +--------+
|  User  |     | Order  |     |Payment |
|Service |     |Service |     |Service |
|  DB-A  |     |  DB-B  |     |  DB-C  |
+---+----+     +---+----+     +---+----+
    |              |               |
    v              v               v
  [REST/gRPC]  [Kafka]        [REST/gRPC]

核心(かくしん)原則(げんそく):

  • ビジネス能力(のうりょく)中心(ちゅうしん)の分離(ぶんり)
  • 「Dumb Pipes, Smart Endpoints」
  • サービス別(べつ)独立(どくりつ)データストア
  • 独立(どくりつ)したデプロイとスケーリング
  • 障害(しょうがい)隔離(かくり)(Fault Isolation)

1.4 モジュラーモノリス — 2025年トレンド

MSAの複雑性(ふくざつせい)なしにモノリスの利点(りてん)を維持(いじ)しながら、モジュール間(かん)の境界(きょうかい)を明確(めいかく)にするアーキテクチャです。

+------------------------------------------+
|           Modular Monolith               |
|  +----------+  +----------+  +--------+  |
|  |   User   |  |  Order   |  |Payment |  |
|  |  Module   |  |  Module  |  | Module |  |
|  | [Schema] |  | [Schema] |  |[Schema]|  |
|  | [API]    |  | [API]    |  | [API]  |  |
|  +----------+  +----------+  +--------+  |
|       |Internal API|   |Internal API|    |
|  +----------------------------------+    |
|  |     Shared Runtime (Single DB)   |    |
|  +----------------------------------+    |
+------------------------------------------+

核心(かくしん)特性(とくせい):

  • 単一(たんいつ)デプロイ単位(たんい)、しかしモジュール間(かん)境界(きょうかい)は厳格(げんかく)
  • モジュール間(かん)通信(つうしん)は公開(こうかい)API(内部(ないぶ)インターフェース)を通(とお)してのみ
  • 各(かく)モジュールは自身(じしん)のデータベーススキーマを所有(しょゆう)
  • 必要(ひつよう)に応(おう)じて個別(こべつ)モジュールをサービスとして抽出(ちゅうしゅつ)可能(かのう)

1.5 アーキテクチャ進化タイムライン

年代アーキテクチャ主導企業核心技術
2000sSOAIBM, OracleESB, SOAP, WSDL
2010s前半MSA台頭Netflix, AmazonREST, Docker
2015-2020MSA全盛期Uber, SpotifyK8s, Istio, gRPC
2020-2023MSA疲労感多数のスタートアップ複雑性爆発
2024-2025モジュラーモノリス復活Shopify, BasecampVertical Slices

2. MSAが過剰な場合:反省と教訓

2.1 DHHのMajestic Monolith

Ruby on Rails創設者(そうせつしゃ)のDavid Heinemeier Hanssonは「マイクロサービスはほとんどのチームにとって不要(ふよう)な複雑性(ふくざつせい)」と強(つよ)く主張(しゅちょう)しています。BasecampとHEYは数百万(すうひゃくまん)ユーザーを単一(たんいつ)モノリスでサービスしています。

核心(かくしん)論点(ろんてん):

  • ほとんどのWebアプリケーションは単一(たんいつ)サーバーで十分(じゅうぶん)
  • MSAの運用(うんよう)複雑性(ふくざつせい)はチームの速度(そくど)を低下(ていか)させる
  • マイクロサービスは100名(めい)以上(いじょう)のエンジニアリング組織(そしき)でのみ意味(いみ)がある

2.2 Amazon Prime Videoの事例

2023年(ねん)、Amazon Prime Videoチームはマイクロサービスアーキテクチャからモノリスに移行(いこう)してコストを90%削減(さくげん)したと発表(はっぴょう)しました。

元(もと)のMSAアーキテクチャの問題(もんだい):

  • AWS Step Functionsによるオーケストレーション → 状態(じょうたい)遷移(せんい)コスト過大(かだい)
  • サービス間(かん)データ転送(てんそう)にS3使用(しよう) → I/Oコスト爆発(ばくはつ)
  • マイクロサービス間(かん)のネットワーク遅延(ちえん)でリアルタイム処理(しょり)不可能(ふかのう)

モノリス移行後(いこうご):

  • インフラコスト90%削減(さくげん)
  • アーキテクチャ簡素化(かんそか)でデバッグ効率(こうりつ)向上(こうじょう)
  • 同(おな)じプロセス内(ない)の関数(かんすう)呼(よ)び出(だ)しで遅延(ちえん)時間(じかん)最小化(さいしょうか)

2.3 SegmentのMSAからモノリス回帰

Segmentは140個(こ)以上(いじょう)のマイクロサービスを運用(うんよう)した後(のち)、再(ふたた)びモノリスに統合(とうごう)しました。

問題点(もんだいてん):

  • 140個(こ)のサービスの同一(どういつ)コード変更(へんこう)を同期(どうき)するのが困難(こんなん)
  • サービス別(べつ)独立(どくりつ)デプロイがかえって統合(とうごう)テストを不可能(ふかのう)にした
  • インフラコストがビジネス成長率(せいちょうりつ)を超過(ちょうか)

教訓(きょうくん): サービスを分離(ぶんり)する前(まえ)に「このサービスは独立(どくりつ)してデプロイ・スケーリングする必要(ひつよう)があるか?」を必(かなら)ず検証(けんしょう)すべきです。


3. モジュラーモノリス深堀り

3.1 Vertical Sliceアーキテクチャ

従来(じゅうらい)の階層型(かいそうがた)(Layered)アーキテクチャの代(か)わりに、機能(きのう)単位(たんい)(Feature)でコードを垂直(すいちょく)分割(ぶんかつ)します。

従来の階層型:
Controllers/ -> Services/ -> Repositories/ -> Models/

Vertical Slice:
Features/
  CreateOrder/
    CreateOrderCommand.cs
    CreateOrderHandler.cs
    CreateOrderValidator.cs
    CreateOrderEndpoint.cs
  GetOrderById/
    GetOrderByIdQuery.cs
    GetOrderByIdHandler.cs
    GetOrderByIdEndpoint.cs
// Vertical Sliceの例 - MediatRパターン
public record CreateOrderCommand(
    string CustomerId,
    List<OrderItem> Items
) : IRequest<OrderResult>;

public class CreateOrderHandler
    : IRequestHandler<CreateOrderCommand, OrderResult>
{
    private readonly OrderDbContext _db;
    private readonly IEventBus _eventBus;

    public CreateOrderHandler(OrderDbContext db, IEventBus eventBus)
    {
        _db = db;
        _eventBus = eventBus;
    }

    public async Task<OrderResult> Handle(
        CreateOrderCommand cmd,
        CancellationToken ct)
    {
        var order = Order.Create(cmd.CustomerId, cmd.Items);
        _db.Orders.Add(order);
        await _db.SaveChangesAsync(ct);

        await _eventBus.Publish(new OrderCreatedEvent(order.Id));
        return new OrderResult(order.Id, order.TotalAmount);
    }
}

3.2 モジュール境界の設定

// モジュール間通信は必ず公開インターフェースを通じて
// order-module/src/main/java/com/app/order/api/
public interface OrderModuleApi {
    OrderDto getOrder(String orderId);
    OrderDto createOrder(CreateOrderRequest request);
    void cancelOrder(String orderId);
}

// order-module/src/main/java/com/app/order/internal/
// このパッケージのクラスは外部モジュールからアクセス不可
class OrderServiceImpl implements OrderModuleApi {
    private final OrderRepository repository;
    private final PaymentModuleApi paymentModule;

    @Override
    public OrderDto createOrder(CreateOrderRequest request) {
        Order order = Order.create(request);
        repository.save(order);
        paymentModule.initiatePayment(order.getId(), order.getTotal());
        return OrderDto.from(order);
    }
}

3.3 Spring Modulith実践

Spring ModulithはモジュラーモノリスのためのSpring公式(こうしき)フレームワークです。

// モジュール構造
com.example.app/
  order/           // Orderモジュール(ルートパッケージ)
    OrderService.java
    Order.java
    internal/      // 外部アクセス不可
      OrderRepository.java
      OrderEventHandler.java
  payment/         // Paymentモジュール
    PaymentService.java
    internal/
      PaymentProcessor.java
  inventory/       // Inventoryモジュール
    InventoryService.java
// Spring Modulithイベントベースのモジュール間通信
@Service
@RequiredArgsConstructor
public class OrderService {

    private final ApplicationEventPublisher events;

    @Transactional
    public Order createOrder(CreateOrderRequest request) {
        var order = new Order(request.customerId(), request.items());
        orderRepo.save(order);

        // イベント発行 — Paymentモジュールが非同期で受信
        events.publishEvent(new OrderCreated(order.getId(), order.getTotal()));
        return order;
    }
}

// Paymentモジュールのイベントハンドラー
@Service
public class PaymentEventHandler {

    @ApplicationModuleListener
    public void onOrderCreated(OrderCreated event) {
        paymentService.processPayment(event.orderId(), event.amount());
    }
}
// モジュール構造検証テスト
@Test
void verifyModularStructure() {
    ApplicationModules modules = ApplicationModules.of(Application.class);
    modules.verify(); // 循環依存性、パッケージアクセス違反を検証
}

4. DDD基盤のサービス分解戦略

4.1 Bounded Contextの識別

Domain-Driven Designにおいて、バウンデッドコンテキストはマイクロサービス分離(ぶんり)の核心(かくしん)基準(きじゅん)です。

+----------------+     +------------------+     +----------------+
|   Order BC     |     |   Payment BC     |     | Inventory BC   |
|                |     |                  |     |                |
| - Order        |     | - Payment        |     | - Product      |
| - OrderLine    |     | - Transaction    |     | - Stock        |
| - Customer(ref)|     | - Order(ref)     |     | - Warehouse    |
+-------+--------+     +--------+---------+     +-------+--------+
        |                       |                       |
        +----------- Events ---------------------+------+

Context Mappingパターン:

パターン説明使用場面
Shared Kernel2つのコンテキストがコード/モデル共有密接なチーム間
Customer-SupplierアップストリームがダウンストリームにAPI提供チーム間依存関係
Conformistダウンストリームがアップストリームモデルをそのまま受容外部サービス統合
Anti-Corruption Layer翻訳レイヤーで外部モデルを遮断レガシー統合
Open Host Service標準プロトコルで公開API提供多数のコンシューマー
Published Language共有スキーマ(JSON Schema, Protobuf)イベント駆動

4.2 Event Storming

Event Stormingはビジネス専門家(せんもんか)と開発者(かいはつしゃ)が一緒(いっしょ)にドメインを探索(たんさく)するワークショップ技法(ぎほう)です。

[オレンジ] Domain Event: 「注文が作成された」
[] Command: 「注文作成」
[] Aggregate: 「Order」
[ピンク] External System: 「決済ゲートウェイ」
[] Policy: 「注文作成時に在庫を減らす」
[] Hot Spot: 「決済失敗時の在庫復旧は?」

タイムライン:
注文作成 -> 在庫確認 -> 決済要求 -> 決済完了 -> 出荷開始
                                  -> 決済失敗 -> 在庫復旧 -> 注文キャンセル

5. 通信パターン:同期 vs 非同期

5.1 同期通信の比較

基準REST (HTTP/JSON)gRPC (HTTP/2, Protobuf)GraphQL
プロトコルHTTP/1.1 or 2HTTP/2HTTP/1.1 or 2
シリアライズJSON(テキスト)Protobuf(バイナリ)JSON(テキスト)
パフォーマンス普通高い(10倍速い)普通
ストリーミング制限的双方向Subscription
コード生成OpenAPI(任意)必須(protoファイル)任意
ブラウザ対応完全gRPC-Web必要完全
最適な用途外部API内部サービス間BFF、モバイル

5.2 gRPCサービス定義

// order_service.proto
syntax = "proto3";
package order;

service OrderService {
  // Unary RPC
  rpc CreateOrder(CreateOrderRequest) returns (OrderResponse);
  rpc GetOrder(GetOrderRequest) returns (OrderResponse);

  // Server Streaming
  rpc WatchOrderStatus(GetOrderRequest) returns (stream OrderStatusUpdate);

  // Bidirectional Streaming
  rpc ChatSupport(stream ChatMessage) returns (stream ChatMessage);
}

message CreateOrderRequest {
  string customer_id = 1;
  repeated OrderItem items = 2;
  ShippingAddress shipping_address = 3;
}

message OrderItem {
  string product_id = 1;
  int32 quantity = 2;
  double unit_price = 3;
}

message OrderResponse {
  string order_id = 1;
  OrderStatus status = 2;
  double total_amount = 3;
  google.protobuf.Timestamp created_at = 4;
}

enum OrderStatus {
  ORDER_STATUS_UNSPECIFIED = 0;
  ORDER_STATUS_PENDING = 1;
  ORDER_STATUS_CONFIRMED = 2;
  ORDER_STATUS_SHIPPED = 3;
  ORDER_STATUS_DELIVERED = 4;
  ORDER_STATUS_CANCELLED = 5;
}

5.3 非同期通信の比較

基準Apache KafkaRabbitMQNATS
モデルログベースストリームメッセージキューPub/Sub + キュー
スループット非常に高い(数百万TPS)高い(数万TPS)非常に高い
メッセージ保持永続保持可能消費後削除デフォルト非保持
順序保証パーティション内保証キュー内保証非保証
再処理オフセットリセットで可能不可能(DLQ活用)JetStreamで可能
最適な用途イベントソーシング、大量処理タスクキュー、RPC軽量メッセージング

5.4 Kafkaイベント駆動通信

// イベント定義
public record OrderCreatedEvent(
    String eventId,
    String orderId,
    String customerId,
    BigDecimal totalAmount,
    List<OrderItemDto> items,
    Instant occurredAt
) {}

// Producer (Order Service)
@Service
@RequiredArgsConstructor
public class OrderEventPublisher {

    private final KafkaTemplate<String, OrderCreatedEvent> kafkaTemplate;

    public void publishOrderCreated(Order order) {
        var event = new OrderCreatedEvent(
            UUID.randomUUID().toString(),
            order.getId(),
            order.getCustomerId(),
            order.getTotalAmount(),
            order.getItems().stream().map(OrderItemDto::from).toList(),
            Instant.now()
        );

        kafkaTemplate.send("order-events", order.getId(), event)
            .whenComplete((result, ex) -> {
                if (ex != null) {
                    log.error("Failed to publish event: {}", ex.getMessage());
                } else {
                    log.info("Event published to partition {} offset {}",
                        result.getRecordMetadata().partition(),
                        result.getRecordMetadata().offset());
                }
            });
    }
}

// Consumer (Payment Service)
@Service
public class PaymentEventConsumer {

    @KafkaListener(
        topics = "order-events",
        groupId = "payment-service",
        containerFactory = "kafkaListenerContainerFactory"
    )
    public void handleOrderCreated(
        @Payload OrderCreatedEvent event,
        @Header(KafkaHeaders.RECEIVED_PARTITION) int partition,
        @Header(KafkaHeaders.OFFSET) long offset
    ) {
        log.info("Received OrderCreated: orderId={}, partition={}, offset={}",
            event.orderId(), partition, offset);

        paymentService.processPayment(event.orderId(), event.totalAmount());
    }
}

6. Service Mesh比較と実践

6.1 Service Meshアーキテクチャ

Service Meshはサービス間(かん)通信(つうしん)をインフラレベルで管理(かんり)します。サイドカープロキシが全(すべ)てのネットワークトラフィックをインターセプトして処理(しょり)します。

+---------------------------------------------+
|                  Service A Pod               |
|  +-------------+     +------------------+   |
|  | Application | --> | Envoy Sidecar    |   |
|  | Container   | <-- | Proxy            |   |
|  +-------------+     +------------------+   |
+---------------------------------------------+
         |  mTLS   |
+---------------------------------------------+
|                  Service B Pod               |
|  +------------------+     +-------------+   |
|  | Envoy Sidecar    | --> | Application |   |
|  | Proxy            | <-- | Container   |   |
|  +------------------+     +-------------+   |
+---------------------------------------------+
         |
+---------------------------------------------+
|            Control Plane (Istiod)            |
| - Certificate Authority (mTLS)              |
| - Configuration Distribution                |
| - Service Discovery                         |
+---------------------------------------------+

6.2 Istio vs Linkerd vs Consul Connect

機能IstioLinkerdConsul Connect
データプレーンEnvoylinkerd2-proxy (Rust)Envoy / built-in
リソース使用量高い低い中程度
学習曲線急勾配緩やか中程度
mTLS自動自動自動
トラフィック管理非常に豊富基本的基本的
オブザーバビリティKiali, JaegerViz DashboardConsul UI
マルチクラスター対応対応強力に対応
WASM拡張対応非対応非対応
推奨用途大規模/複雑な環境軽量/シンプルな環境HashiCorpスタック

6.3 Istioトラフィック管理

# VirtualService - カナリーデプロイ
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: order-service
spec:
  hosts:
    - order-service
  http:
    - match:
        - headers:
            x-canary:
              exact: "true"
      route:
        - destination:
            host: order-service
            subset: canary
          weight: 100
    - route:
        - destination:
            host: order-service
            subset: stable
          weight: 90
        - destination:
            host: order-service
            subset: canary
          weight: 10
---
# DestinationRule - サブセット定義
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: order-service
spec:
  host: order-service
  trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 100
      http:
        h2UpgradePolicy: UPGRADE
    outlierDetection:
      consecutive5xxErrors: 5
      interval: 30s
      baseEjectionTime: 30s
  subsets:
    - name: stable
      labels:
        version: v1
    - name: canary
      labels:
        version: v2

7. 分散トランザクション:Sagaパターン

7.1 Choreography vs Orchestration

分散(ぶんさん)環境(かんきょう)では2PC(Two-Phase Commit)はパフォーマンスと可用性(かようせい)の問題(もんだい)で非実用的(ひじつようてき)です。Sagaパターンはローカルトランザクションのシーケンスで分散(ぶんさん)トランザクションを管理(かんり)します。

Choreography(イベントベース):

Order Service        Payment Service      Inventory Service
     |                      |                      |
     | OrderCreated         |                      |
     |--------------------->|                      |
     |                      | PaymentProcessed     |
     |                      |--------------------->|
     |                      |                      | InventoryReserved
     |                      |                      |----->
     |                      |                      |
     |         [失敗時の補償トランザクション]        |
     |                      |                      |
     |                      | PaymentFailed        |
     |                      |--------------------->|
     |                      |                      | InventoryReleased
     | OrderCancelled       |                      |
     |<---------------------|                      |

Orchestration(中央コーディネーター):

          Order Saga Orchestrator
                   |
    +--------------+--------------+
    |              |              |
    v              v              v
Order Service  Payment Service  Inventory Service
  create()     processPayment()  reserveStock()
  cancel()     refund()          releaseStock()

7.2 TemporalベースのSaga Orchestration

// Temporal Workflow定義
func OrderSagaWorkflow(ctx workflow.Context, input OrderInput) (OrderResult, error) {
    logger := workflow.GetLogger(ctx)
    var result OrderResult

    activityOpts := workflow.ActivityOptions{
        StartToCloseTimeout: 30 * time.Second,
        RetryPolicy: &temporal.RetryPolicy{
            InitialInterval:    time.Second,
            BackoffCoefficient: 2.0,
            MaximumInterval:    time.Minute,
            MaximumAttempts:    3,
        },
    }
    ctx = workflow.WithActivityOptions(ctx, activityOpts)

    // Step 1: 注文作成
    var orderID string
    err := workflow.ExecuteActivity(ctx, CreateOrderActivity, input).Get(ctx, &orderID)
    if err != nil {
        return result, fmt.Errorf("create order failed: %w", err)
    }

    // Step 2: 決済処理
    var paymentID string
    err = workflow.ExecuteActivity(ctx, ProcessPaymentActivity, orderID, input.Amount).Get(ctx, &paymentID)
    if err != nil {
        // 補償トランザクション: 注文キャンセル
        logger.Info("Payment failed, cancelling order", "orderID", orderID)
        _ = workflow.ExecuteActivity(ctx, CancelOrderActivity, orderID).Get(ctx, nil)
        return result, fmt.Errorf("payment failed: %w", err)
    }

    // Step 3: 在庫確保
    err = workflow.ExecuteActivity(ctx, ReserveInventoryActivity, orderID, input.Items).Get(ctx, nil)
    if err != nil {
        // 補償トランザクション: 返金 + 注文キャンセル
        logger.Info("Inventory reservation failed, compensating", "orderID", orderID)
        _ = workflow.ExecuteActivity(ctx, RefundPaymentActivity, paymentID).Get(ctx, nil)
        _ = workflow.ExecuteActivity(ctx, CancelOrderActivity, orderID).Get(ctx, nil)
        return result, fmt.Errorf("inventory reservation failed: %w", err)
    }

    result = OrderResult{
        OrderID:   orderID,
        PaymentID: paymentID,
        Status:    "CONFIRMED",
    }
    return result, nil
}

7.3 Transactional Outboxパターン

イベント発行(はっこう)の原子性(げんしせい)を保証(ほしょう)するために、イベントをDBテーブルに先(さき)に保存(ほぞん)した後(あと)、別(べつ)のプロセスが発行(はっこう)します。

-- Outboxテーブル
CREATE TABLE outbox_events (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    aggregate_type VARCHAR(255) NOT NULL,
    aggregate_id VARCHAR(255) NOT NULL,
    event_type VARCHAR(255) NOT NULL,
    payload JSONB NOT NULL,
    created_at TIMESTAMP DEFAULT NOW(),
    published_at TIMESTAMP NULL
);
// Outboxパターン実装
@Service
@RequiredArgsConstructor
public class OrderService {

    private final OrderRepository orderRepo;
    private final OutboxRepository outboxRepo;

    @Transactional // 注文保存とイベント保存が一つのトランザクション
    public Order createOrder(CreateOrderRequest request) {
        Order order = Order.create(request);
        orderRepo.save(order);

        OutboxEvent event = OutboxEvent.builder()
            .aggregateType("Order")
            .aggregateId(order.getId())
            .eventType("OrderCreated")
            .payload(toJson(new OrderCreatedEvent(order)))
            .build();
        outboxRepo.save(event);

        return order;
    }
}

8. オブザーバビリティ:OpenTelemetryスタック

8.1 オブザーバビリティの3要素

+---------------------------------------------------+
|                  Observability                    |
|                                                   |
|  +--------+    +---------+    +---------+         |
|  | Logs   |    | Metrics |    | Traces  |         |
|  | (What) |    | (How)   |    | (Where) |         |
|  +--------+    +---------+    +---------+         |
|                                                   |
|  「エラー発生」「遅延増加」 「どこで遅い?」         |
+---------------------------------------------------+

8.2 OpenTelemetry設定

# otel-collector-config.yaml
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

processors:
  batch:
    send_batch_size: 1024
    timeout: 5s

exporters:
  prometheusremotewrite:
    endpoint: "http://prometheus:9090/api/v1/write"
  otlp/jaeger:
    endpoint: "jaeger:4317"
    tls:
      insecure: true
  loki:
    endpoint: "http://loki:3100/loki/api/v1/push"

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlp/jaeger]
    metrics:
      receivers: [otlp]
      processors: [batch]
      exporters: [prometheusremotewrite]
    logs:
      receivers: [otlp]
      processors: [batch]
      exporters: [loki]

8.3 分散トレーシング実装

// Spring Boot + OpenTelemetry自動計装
@Service
public class OrderService {

    private final Tracer tracer;

    public Order createOrder(CreateOrderRequest request) {
        Span span = tracer.spanBuilder("createOrder")
            .setAttribute("order.customer_id", request.getCustomerId())
            .setAttribute("order.item_count", request.getItems().size())
            .startSpan();

        try (Scope scope = span.makeCurrent()) {
            Order order = processOrder(request);
            span.setAttribute("order.id", order.getId());
            span.setStatus(StatusCode.OK);
            return order;
        } catch (Exception e) {
            span.setStatus(StatusCode.ERROR, e.getMessage());
            span.recordException(e);
            throw e;
        } finally {
            span.end();
        }
    }
}

8.4 主要メトリクス(RED Method)

RED Method(サービスレベルメトリクス):
- Rate: 秒あたりのリクエスト数
- Errors: エラー率
- Duration: レイテンシパーセンタイル

USE Method(インフラレベルメトリクス):
- Utilization: CPU/メモリ使用率
- Saturation: キュー深度、待機スレッド数
- Errors: システムエラー数

9. API Gatewayパターン

9.1 API Gatewayの役割

Client (Web/Mobile/Partner)
         |
         v
+---------------------+
|    API Gateway       |
| - ルーティング       |
| - 認証/認可          |
| - Rate Limiting      |
| - ロードバランシング |
| - キャッシング       |
| - リクエスト変換     |
| - Circuit Breaker    |
+---------------------+
    |       |       |
    v       v       v
  User   Order  Payment
 Service Service Service

9.2 主要API Gateway比較

機能KongAWS API GatewayNGINXEnvoy
タイプOSS + EnterpriseマネージドOSSOSS
プラグイン豊富(Lua)Lambda統合モジュールFilter Chain
パフォーマンス高い中程度非常に高い非常に高い
K8s統合Ingress Controller-Ingress ControllerGateway API
gRPC対応対応制限的ネイティブ
コスト自己運用リクエスト課金自己運用自己運用

10. デプロイ戦略

10.1 デプロイ戦略比較

戦略ダウンタイムロールバック速度リソースコストリスク
Rolling Updateなし遅い低い中程度
Blue-Greenなし即時2倍低い
Canaryなし速いやや追加非常に低い
A/B Testingなし速いやや追加低い

10.2 Argo Rolloutsによるカナリーデプロイ

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: order-service
spec:
  replicas: 10
  strategy:
    canary:
      steps:
        - setWeight: 5
        - pause:
            duration: 5m
        - analysis:
            templates:
              - templateName: success-rate
        - setWeight: 25
        - pause:
            duration: 10m
        - setWeight: 50
        - pause:
            duration: 10m
        - setWeight: 100
      canaryService: order-service-canary
      stableService: order-service-stable
  selector:
    matchLabels:
      app: order-service
  template:
    metadata:
      labels:
        app: order-service
    spec:
      containers:
        - name: order-service
          image: registry.example.com/order-service:v2.1.0
          ports:
            - containerPort: 8080
          resources:
            requests:
              cpu: 250m
              memory: 512Mi
            limits:
              cpu: 500m
              memory: 1Gi

11. マイグレーション戦略:モノリスからMSAへ

11.1 Strangler Figパターン

既存(きぞん)システムを包(つつ)みながら、段階的(だんかいてき)に新(あたら)しいシステムにトラフィックを移行(いこう)します。

Phase 1: プロキシ導入
+--------+     +-------+     +-----------+
| Client | --> | Proxy | --> | Monolith  |
+--------+     +-------+     +-----------+

Phase 2: 一部機能の抽出
+--------+     +-------+---> +-----------+
| Client | --> | Proxy |     | Monolith  |
+--------+     +---+---+     +-----------+
                   |
                   +--------> +-----------+
                              | New User  |
                              | Service   |
                              +-----------+

Phase 3: 段階的な移行完了
+--------+     +-------+---> +-----------+
| Client | --> | Proxy |     | Monolith  | (縮小)
+--------+     +---+---+     +-----------+
                   |
                   +--------> +-----------+
                   |          | User Svc  |
                   +--------> +-----------+
                   |          | Order Svc |
                   +--------> +-----------+
                              | Pay Svc   |
                              +-----------+

11.2 Branch by Abstraction

// Step 1: 抽象化レイヤー導入
public interface NotificationService {
    void sendEmail(String to, String subject, String body);
    void sendSms(String to, String message);
}

// Step 2: 既存実装のラッピング
public class LegacyNotificationService implements NotificationService {
    private final MonolithNotificationModule legacy;

    public void sendEmail(String to, String subject, String body) {
        legacy.email(to, subject, body);
    }
}

// Step 3: 新実装の開発
public class NewNotificationService implements NotificationService {
    private final EmailClient emailClient;
    private final SmsGateway smsGateway;

    public void sendEmail(String to, String subject, String body) {
        emailClient.send(to, subject, body);
    }
}

// Step 4: Feature Flagで切り替え
@Service
public class NotificationServiceRouter implements NotificationService {

    private final LegacyNotificationService legacy;
    private final NewNotificationService modern;
    private final FeatureFlags flags;

    public void sendEmail(String to, String subject, String body) {
        if (flags.isEnabled("use-new-notification-service")) {
            modern.sendEmail(to, subject, body);
        } else {
            legacy.sendEmail(to, subject, body);
        }
    }
}

12. アンチパターン:これだけは避けよう

12.1 分散モノリス

MSAの形(かたち)を持(も)ちながら、モノリスの全(すべ)てのデメリットと分散(ぶんさん)システムの複雑性(ふくざつせい)を併(あわ)せ持(も)つ最悪(さいあく)の状態(じょうたい)です。

悪い例:
Service A --sync--> Service B --sync--> Service C --sync--> Service D
   |                    |                    |
   +------------ 共有データベース -----------+

良い例:
Service A --event--> Service B --event--> Service C
   [DB-A]              [DB-B]              [DB-C]

12.2 ナノサービス

サービスが小(ちい)さすぎて独立(どくりつ)して意味(いみ)がなく、運用(うんよう)オーバーヘッドだけが増加(ぞうか)します。

悪い例:
- User Profile Service
- User Address Service
- User Preference Service
- User Avatar Service
- User Notification Settings Service
-> 5サービス + 5DB + 5CI/CD + 5モニタリング

良い例:
- User Service(Profile, Address, Preference, Avatar統合)
-> 1サービス、内部モジュールで分離

12.3 同期呼び出し地獄

問題:
Client -> API GW -> Auth -> User -> Order -> Inventory -> Payment
全体遅延 = 各サービス遅延の合計
全体可用性 = 各サービス可用性の積
(99.9%)^6 = 99.4%(年間52時間のダウンタイム!)

解決策:
1. 非同期メッセージングに切り替え
2. CQRSで読み取りを最適化
3. 必須パスのみ同期、残りはイベント駆動

13. 意思決定フレームワーク

13.1 チーム規模別推奨アーキテクチャ

開発者1-5:
  -> モノリス(Simple is best)

開発者5-20:
  -> モジュラーモノリス(モジュール境界設定)

開発者20-50:
  -> モジュラーモノリス + コアサービス2-3個分離

開発者50-200:
  -> MSA(チーム単位のサービスオーナーシップ)

開発者200+:
  -> MSA + Platform Engineering

13.2 決定マトリクス

基準モノリスモジュラーモノリスMSA
チーム規模1-10名5-50名20名+
デプロイ頻度週1回以下週数回日数十回
スケーリング均一部分的サービス別独立
技術多様性単一スタック単一スタックポリグロット
運用能力低くてもOK中程度高い必要あり
初期速度速い速い遅い
障害隔離不可制限的完全隔離

14. 面接対策:マイクロサービス核心質問20選

Q1. マイクロサービスとモノリスの違いを説明してください。

モノリスは全(すべ)ての機能(きのう)が一(ひと)つのデプロイ単位(たんい)で構成(こうせい)され、マイクロサービスはビジネス能力(のうりょく)単位(たんい)で独立(どくりつ)してデプロイ・スケーリング可能(かのう)な小(ちい)さなサービス群(ぐん)で構成(こうせい)されます。モノリスはトランザクション管理(かんり)が簡単(かんたん)ですがスケーラビリティに限界(げんかい)があり、MSAは独立(どくりつ)デプロイ・スケーリングが可能(かのう)ですが分散(ぶんさん)システムの複雑性(ふくざつせい)が増加(ぞうか)します。

Q2. サービス分解の基準は何ですか?

DDDのBounded Contextが最(もっと)も重要(じゅうよう)な基準(きじゅん)です。ドメインモデルが一貫性(いっかんせい)を維持(いじ)する境界(きょうかい)を識別(しきべつ)し、その境界(きょうかい)に沿(そ)ってサービスを分離(ぶんり)します。さらに独立(どくりつ)デプロイの必要性(ひつようせい)、スケーリング要件(ようけん)の差異(さい)、チームオーナーシップ、技術(ぎじゅつ)スタックの違(ちが)いを考慮(こうりょ)します。

Q3. SagaパターンのChoreographyとOrchestrationの違いを説明してください。

Choreographyは各(かく)サービスがイベントを発行(はっこう)・購読(こうどく)して自律的(じりつてき)に進行(しんこう)します。中央(ちゅうおう)コーディネーターがなく疎結合(そけつごう)ですが、フロー追跡(ついせき)が困難(こんなん)です。Orchestrationは中央(ちゅうおう)コーディネーター(Temporal、Camunda等(とう))が全体(ぜんたい)フローを制御(せいぎょ)します。ビジネスロジックが一箇所(いっかしょ)に集(あつ)まり可視性(かしせい)が良(よ)いですが、単一障害点(たんいつしょうがいてん)になりえます。

Q4. Service Meshが必要な理由は何ですか?

サービス数(すう)が増加(ぞうか)すると、サービス間(かん)通信(つうしん)の共通(きょうつう)関心事(かんしんじ)(mTLS、ロードバランシング、サーキットブレーカー、リトライ、オブザーバビリティ)を各(かく)サービスに実装(じっそう)するのが困難(こんなん)になります。Service Meshはこれをインフラレベル(サイドカープロキシ)で透過的(とうかてき)に処理(しょり)し、アプリケーションコードをクリーンに保(たも)ちます。

Q5. 分散モノリスとは何か、どう防止しますか?

分散(ぶんさん)モノリスはMSAの形態(けいたい)を持(も)ちながら、サービス間(かん)の強(つよ)い結合(けつごう)により独立(どくりつ)デプロイが不可能(ふかのう)な状態(じょうたい)です。防止(ぼうし)するには非同期(ひどうき)通信(つうしん)優先(ゆうせん)、サービス別(べつ)独立(どくりつ)データベース、APIバージョニング、Consumer-Driven Contract Testingを適用(てきよう)します。

Q6. gRPCがRESTより有利な場合はいつですか?

内部(ないぶ)サービス間(かん)通信(つうしん)でgRPCが有利(ゆうり)です。ProtobufバイナリシリアライゼーションはJSON比(ひ)で10倍(ばい)以上(いじょう)速(はや)く、HTTP/2ベースのマルチプレクシングと双方向(そうほうこう)ストリーミングをサポートします。コード生成(せいせい)で型安全(かたあんぜん)なAPIを保証(ほしょう)します。一方(いっぽう)、ブラウザ直接(ちょくせつ)呼(よ)び出(だ)しが必要(ひつよう)な外部(がいぶ)APIにはRESTが適(てき)しています。

Q7. Transactional Outboxパターンを説明してください。

イベント発行(はっこう)の原子性(げんしせい)を保証(ほしょう)するパターンです。ビジネスデータ変更(へんこう)とイベントを同(おな)じDBトランザクションで保存(ほぞん)(outboxテーブル)し、別(べつ)プロセス(Debezium CDCまたはポーラー)がoutboxテーブルのイベントをメッセージブローカーに送信(そうしん)します。DBトランザクションがロールバックされればイベントも一緒(いっしょ)にロールバックされます。

Q8. CQRSはいつ使用しますか?

Command(書(か)き込(こ)み)とQuery(読(よ)み取(と)り)の要件(ようけん)が大(おお)きく異(こと)なる時(とき)に使用(しよう)します。例(たと)えば、書(か)き込(こ)みは正規化(せいきか)されたRDBMS、読(よ)み取(と)りは非正規化(ひせいきか)されたNoSQL/Elasticsearchで最適化(さいてきか)できます。Event Sourcingと共(とも)に使(つか)うと強力(きょうりょく)ですが、複雑性(ふくざつせい)が増(ま)すため、ホットスポット機能(きのう)にのみ適用(てきよう)するのが良(よ)いです。

Q9. カナリーデプロイとBlue-Greenデプロイの違いを説明してください。

Blue-Greenは2つの同一(どういつ)環境(かんきょう)を維持(いじ)しトラフィックを一度(いちど)に切(き)り替(か)えます。即時(そくじ)ロールバック可能(かのう)ですがリソースが2倍(ばい)必要(ひつよう)です。カナリーは少数(しょうすう)のトラフィック(5-10%)のみ新(あたら)しいバージョンに送(おく)り、メトリクスを確認(かくにん)しながら段階的(だんかいてき)に比率(ひりつ)を上(あ)げます。リスクは低(ひく)いですが完了(かんりょう)に時間(じかん)がかかります。

Q10. OpenTelemetryの役割を説明してください。

OpenTelemetryは分散(ぶんさん)システムのオブザーバビリティのための統一(とういつ)標準(ひょうじゅん)です。Traces、Metrics、Logsを単一(たんいつ)SDKで収集(しゅうしゅう)し、ベンダー中立(ちゅうりつ)のOTLPプロトコルで様々(さまざま)なバックエンド(Jaeger、Prometheus、Grafana)に送信(そうしん)します。

Q11. モジュラーモノリスが2025年に注目される理由は?

MSAの運用(うんよう)複雑性(ふくざつせい)を経験(けいけん)した多(おお)くのチームが「必要(ひつよう)だったのは適切(てきせつ)なモジュール境界(きょうかい)であり、別々(べつべつ)のサービスではなかった」と気(き)づきました。モジュラーモノリスはMSAのモジュール性(せい)を維持(いじ)しながら運用(うんよう)複雑性(ふくざつせい)を大幅(おおはば)に削減(さくげん)し、必要(ひつよう)に応(おう)じてサービスを抽出(ちゅうしゅつ)できる柔軟性(じゅうなんせい)を提供(ていきょう)します。

Q12. Strangler Figパターンを説明してください。

レガシーシステムを段階的(だんかいてき)に新(あたら)しいシステムに移行(いこう)するマイグレーションパターンです。プロキシ(API Gateway)を前(まえ)に配置(はいち)し、新(あたら)しい機能(きのう)は新(あたら)しいサービスとして実装(じっそう)し、既存(きぞん)の機能(きのう)も段階的(だんかいてき)に移行(いこう)します。ビッグバンマイグレーションのリスクを軽減(けいげん)します。

Q13. API GatewayとService Meshの違いは何ですか?

API Gatewayは外部(がいぶ)トラフィック(North-South)を処理(しょり)し、認証(にんしょう)、Rate Limiting、API変換(へんかん)を担当(たんとう)します。Service Meshは内部(ないぶ)サービス間(かん)トラフィック(East-West)を管理(かんり)し、mTLS、サーキットブレーカー、ロードバランシング、オブザーバビリティを提供(ていきょう)します。両方(りょうほう)必要(ひつよう)な場合(ばあい)があり、相互(そうご)補完的(ほかんてき)です。

Q14. 冪等性がマイクロサービスで重要な理由は?

ネットワーク障害(しょうがい)によるリトライやメッセージ重複(じゅうふく)が発生(はっせい)しうる分散(ぶんさん)環境(かんきょう)では、同(おな)じリクエストを複数回(ふくすうかい)処理(しょり)しても結果(けっか)が同一(どういつ)でなければなりません。冪等性(べきとうせい)キーの使用(しよう)やデータベースのユニーク制約(せいやく)で実装(じっそう)します。

Q15. Event Sourcingとは何か、いつ使用しますか?

状態(じょうたい)変更(へんこう)をイベントのシーケンスとして保存(ほぞん)するパターンです。現在(げんざい)の状態(じょうたい)はイベントをリプレイして導出(どうしゅつ)します。監査(かんさ)ログが必須(ひっす)な金融(きんゆう)システム、タイムトラベル(特定(とくてい)時点(じてん)の状態(じょうたい)照会(しょうかい))が必要(ひつよう)な場合(ばあい)、CQRSと共(とも)に使用(しよう)すると効果的(こうかてき)です。複雑性(ふくざつせい)が高(たか)いため、全(すべ)てのサービスへの適用(てきよう)は非推奨(ひすいしょう)です。

Q16. Circuit Breakerパターンを説明してください。

外部(がいぶ)サービス呼(よ)び出(だ)し失敗(しっぱい)が閾値(しきいち)を超(こ)えると回路(かいろ)を開(ひら)いて即座(そくざ)に失敗(しっぱい)を返(かえ)すパターンです。Closed(正常(せいじょう))- Open(遮断(しゃだん))- Half-Open(試験的(しけんてき)許可(きょか))の3状態(じょうたい)を循環(じゅんかん)します。障害(しょうがい)伝播(でんぱ)を防止(ぼうし)しシステム全体(ぜんたい)の安定性(あんていせい)を維持(いじ)します。

Q17. Consumer-Driven Contract Testingとは何ですか?

APIコンシューマーが期待(きたい)する契約(けいやく)(Contract)を定義(ていぎ)し、プロバイダーがこの契約(けいやく)を充足(じゅうそく)しているかテストします。Pactフレームワークが代表的(だいひょうてき)です。MSAでの統合(とうごう)テストの困難(こんなん)さを解決(かいけつ)し、API変更(へんこう)がコンシューマーを壊(こわ)さないことを保証(ほしょう)します。

Q18. データ一貫性維持の戦略は何ですか?

強(つよ)い一貫性(いっかんせい)が必要(ひつよう)なら同期(どうき)呼(よ)び出(だ)し + 分散(ぶんさん)トランザクション(Saga)、最終的(さいしゅうてき)一貫性(いっかんせい)が許容(きょよう)されるならイベントベースの非同期(ひどうき)通信(つうしん)を使用(しよう)します。Outboxパターンでイベント発行(はっこう)の原子性(げんしせい)を保証(ほしょう)し、CDC(Change Data Capture)でDB変更(へんこう)をイベントとしてキャプチャできます。

Q19. マイクロサービスでのログ戦略はどう設計しますか?

構造化(こうぞうか)ログ(JSON)、相関(そうかん)ID(Correlation ID)によるリクエスト追跡(ついせき)、中央集権的(ちゅうおうしゅうけんてき)なログ収集(しゅうしゅう)(ELK、Loki)、ログレベルの動的(どうてき)変更(へんこう)機能(きのう)が核心(かくしん)です。OpenTelemetryでログ・トレース・メトリクスを連携(れんけい)するとデバッグ効率(こうりつ)が大幅(おおはば)に向上(こうじょう)します。

Q20. マイクロサービス導入時の最も一般的な間違いは何ですか?
  1. 小(ちい)さすぎるサービス(ナノサービス) 2) 共有(きょうゆう)データベース使用(しよう) 3) 同期(どうき)呼(よ)び出(だ)しチェーンの濫用(らんよう) 4) オブザーバビリティ不備(ふび)でのMSA導入(どうにゅう) 5) チーム構造(こうぞう)変更(へんこう)なしに技術(ぎじゅつ)だけ変更(へんこう) 6) ビッグバンマイグレーション。Conwayの法則(ほうそく)に従(したが)い、チーム構造(こうぞう)がアーキテクチャを決定(けってい)するため、組織(そしき)変化(へんか)が先行(せんこう)すべきです。

15. クイズ

クイズ1. MSAの核心原則でないものは?

A) サービス別独立データベース B) ビジネス能力中心のサービス分離 C) 中央集権的ガバナンス D) 独立デプロイとスケーリング

正解: C

MSAは分散(ぶんさん)ガバナンスを強調(きょうちょう)します。各(かく)チームが自律的(じりつてき)に技術(ぎじゅつ)スタックとデータストアを選択(せんたく)できることが基本(きほん)です。中央集権的(ちゅうおうしゅうけんてき)ガバナンスはSOAの特性(とくせい)です。

クイズ2. Saga Choreographyの欠点は?

A) 中央コーディネーターが単一障害点になる B) ビジネスフローの追跡が困難 C) サービス間結合度が高まる D) イベントブローカーが不要

正解: B

Choreographyは中央(ちゅうおう)コーディネーターなしにイベントベースで動作(どうさ)するため、全体(ぜんたい)のビジネスフロー追跡(ついせき)が困難(こんなん)です。Aは Orchestrationの欠点(けってん)です。

クイズ3. モジュラーモノリスの核心特性でないものは?

A) 単一デプロイ単位 B) モジュール間の公開APIを通じた通信 C) サービス別独立データベース D) 厳格なモジュール境界設定

正解: C

モジュラーモノリスは単一(たんいつ)データベースを使用(しよう)しつつ、モジュール別(べつ)にスキーマを分離(ぶんり)します。サービス別(べつ)独立(どくりつ)データベースはMSAの特性(とくせい)です。

クイズ4. Strangler Figパターンの最初のステップは?

A) レガシーシステムの削除 B) 全機能を新サービスに移行 C) プロキシ/API Gatewayの導入 D) データベース分離

正解: C

Strangler Figパターンの最初(さいしょ)のステップは、トラフィックを制御(せいぎょ)できる単一(たんいつ)エントリポイントを作(つく)るためにプロキシを導入(どうにゅう)することです。

クイズ5. 開発者10名のスタートアップに最適なアーキテクチャは?

A) マイクロサービス B) SOA C) モジュラーモノリス D) Serverless

正解: C

10名(めい)規模(きぼ)のスタートアップにはモジュラーモノリスが最適(さいてき)です。MSAの運用(うんよう)複雑性(ふくざつせい)は負担(ふたん)が大(おお)きく、純粋(じゅんすい)なモノリスよりもモジュール境界(きょうかい)を明確(めいかく)にすることで将来(しょうらい)のサービス分離(ぶんり)に備(そな)えるのが賢明(けんめい)です。


参考資料