Curated Tech Reading Map

次に読むべき技術書が見つかるサイト

ブログ記事

「なんとなく分散」を超えるために──『マイクロサービスパターン』が整理するサーガ・CQRS・契約テスト

著者: DevBookPath 編集部公開日: 更新日:

マイクロサービスへの移行を決断するのは比較的簡単だ。難しいのは、データベースを分割した後にどうトランザクションを管理するか、複数サービスにまたがる検索をどう処理するか、自動テストをどう設計するかという「その後」の問いだ。

Chris Richardson の『マイクロサービスパターン 実践的システムデザインのためのコード解説』(インプレス、2020年)は、フードデリバリーサービス「FTGO」を題材に、Java・Spring Boot・Eventuate Tram を使った動作するコードを通じて、こうした問いへの具体的な回答を示す。コードは Java スタックに依存しているが、設計の考え方は言語を問わず参照できる。

1. サービスをどこで切るか──「ビジネス境界」による分割基準

マイクロサービスへの移行でよくある失敗が、テーブル単位や技術レイヤー単位でサービスを切ってしまう「分散モノリス」だ。これでは開発効率が上がらないどころか、デプロイ依存関係が増えて状況が悪化する。

本書はサービス分割の基準として、ドメイン駆動設計(DDD)の「サブドメイン」と「境界づけられたコンテキスト」を採用する。ビジネス能力ごとに境界を引き、各サービスが独立してデプロイできる状態を目指す設計だ。分割後も依存関係が残る場合は「分散モノリス」のアンチパターンに陥っているサインとして、本書はトレードオフを整理する。

正確に境界を引くことは一度の設計では難しい。本書はドメインの理解が深まるにつれて分割を見直す反復的なアプローチを前提としており、既存モノリスから段階的にサービスを切り出す「Strangler Application パターン」も解説している。

2. 分散環境で整合性をどう保つか──サーガパターンの設計

サービスごとにデータベースを持つ構成では、従来の 2 フェーズコミット(XA)は可用性の低下を招くため推奨されない。本書が代替として提示するのが「サーガ(Saga)パターン」だ。

サーガは、それぞれのサービスがローカルトランザクションを実行し、その完了をイベントやメッセージで次のサービスに通知することで処理の連鎖を作る。途中でエラーが発生した場合は、それまでに完了したトランザクションを逆順に打ち消す「補償トランザクション」を実行して整合性を取り戻す。

サーガの実装方式には 2 種類ある。各サービスがイベントを介して自律的に処理を進める「コレオグラフィ」と、オーケストレーターが全体の処理フローを管理する「オーケストレーション」だ。本書はどちらの方式も FTGO のコードで実装し、並行処理時の不整合(サーガが ACID トランザクションの「分離性」を保証しない点)への対処方法も含めて詳細に論じる。

flowchart LR
    O["注文サービス\n①注文作成"] -->|"注文作成イベント"| I["在庫サービス\n②在庫確保"]
    I -->|"在庫確保イベント"| P["支払いサービス\n③支払い処理"]
    P -->|"✅ 成功"| OK["注文確定"]
    P -->|"❌ 失敗"| CB["補償トランザクション\n在庫解放 → 注文キャンセル"]
    style OK fill:#e8f8e8,stroke:#4caf50
    style CB fill:#fce8e8,stroke:#e53935

3. 横断クエリをどう捌くか──CQRS とイベントソーシングの連携

データベースを分割すると、複数サービスにまたがる JOIN クエリが使えなくなる。注文情報と顧客情報を一覧表示するような処理が、書き込み系のサービス間 API 呼び出しの連鎖になってしまうケースが典型例だ。

本書が提示する解決策が「CQRS(コマンドクエリ責任分離)」だ。書き込み(コマンド)と読み取り(クエリ)のモデルを完全に分離し、読み取り専用のビューを非同期で構築する。イベントソーシングと組み合わせることで、アプリケーションのあらゆる状態変化をイベントとして保存し、そのイベントから任意の読み取りビューを再構築できる構成を実現する。

この設計は導入コストが高い。しかし、読み取りの高速化と書き込みの独立性を両立できるため、スケーラビリティと検索パフォーマンスが問題になるシステムでは選択肢になる。本書は CQRS の複雑さを正直に認めつつ、どのような条件で採用を判断するかを論じる。

4. どんな状況で開けば効くか

「サービスを分割したはいいが、注文と決済のように複数サービスをまたぐ処理で不整合が起きたとき、リカバリーがその場しのぎのコードになっている」——本書が最も効くのはこの状況だ。サーガの補償トランザクションを型として持てば、失敗時の巻き戻しを設計の一部として扱えるようになる。

もう一つは、サービスが増えるほど結合テスト環境が壊れ、E2E テストが不安定になってリリースのたびに足を取られている状況。契約テストを下層に置くと、すべてのサービスを立ち上げずに API の互換性を検証でき、デプロイ判断が速くなる。

5. 読むべき人と、まだ読まなくていい人

向いている人

  • モノリスの肥大化でビルドとデプロイが遅くなり、1 箇所の変更が全体に波及する怖さからリリース速度が落ちているテックリード
  • データベースをサービスごとに分けた結果、横断的な一覧表示の遅延やサービス間の不整合に手を焼いているエンジニア
  • サービスが増えるほど結合テスト環境が壊れ、デプロイ検証がチーム全体のボトルネックになっている SRE・QA リード

向いていない人

  • モノリスを分割すべきか自体をまだ決めかねている人。本書は「分割した後」の実装が主題なので、分割の是非は『モノリスからマイクロサービスへ』で判断軸を固めてからの方が順序が合う
  • Go や Rust など非 Java のスタックで、載っているコードをそのまま動かして学びたい人。サンプルは Java・Spring Boot・Eventuate Tram に依存し、設計思想を自分の言語へ翻訳する負荷がかかる。難易度も上級寄りだ

6. 導入前に知っておきたい限界とコスト

本書のパターンは万能ではなく、採用の判断そのものにコストがかかる。サーガはローカルトランザクションの連鎖で最終的整合性を保つ一方、ACID の「分離性」を犠牲にする。並行して走る処理の不整合を防ぐ手当てを別に組む必要があり、扱いを誤れば本来不要な複雑さを抱え込む過剰設計に傾きやすい。

契約テストやコンポーネントテストも、テストダブルの設計や Docker を使ったプロセス外テストの基盤づくりに、初期の構築コストと運用の手間がかかる。本書はこうしたトレードオフを各パターンの「フォース(目的と制約)」として突き放して並べる。だからこそ、必要な場面を見極めてから使うための地図として読むのが正しい。

7. 576ページをどう読むか──課題から逆引きする

576 ページ・全 13 章を通読する負担は大きいので、いま抱えている課題から逆引きするのが現実的だ。モノリスの限界と分割の基準をつかむなら第 1〜2 章、分散トランザクションで困っているなら第 4 章(サーガ)、横断クエリの遅延なら第 6〜7 章(イベントソーシングと CQRS)へ直接入る。テストの不安定さが主課題なら第 9〜10 章、既存モノリスからの移行が目的なら第 13 章のリファクタリング(Strangler Application)が軸になる。

44 のパターンはカタログとして引ける構成なので、通読して知識を仕込むより、直面した問題の章を開いて実装例と突き合わせる辞書的な使い方が向いている。

8. 読み終えたら、次に開く一冊

本書を読み終えると、関心は「なぜこのパターンが効くのか」の裏付けと、「壊れたときにどうするか」の設計へ分かれる。データ整合性の原理を掘り下げたいなら『データ指向アプリケーションデザイン』へ。複製・分割・トランザクションの理論が、サーガや CQRS の成り立つ理由を裏側から支える。分散システムを実運用する視点がほしいなら『Release It!』が、サーキットブレーカーやバルクヘッドといった障害を連鎖させない安定性パターンを与える。契約テストをさらに詰めたい場合は『Web APIテスト技法』が消費者駆動契約の手順を補う。

実務での最初の一歩は、いま抱えているサービスをまたぐ取引を 1 つ選び、失敗したときの補償トランザクションを設計図に起こすことだ。パターンを自分のシステムの言葉へ翻訳するところから始める。

筆者の体験から

サービス分割の議論が感覚頼りだった時期がある。「このテーブルとあのテーブルで分けよう」という案に誰も自信を持てず、分割後にトランザクションをどう扱うかも見えないまま話だけが先行していた。本書でビジネス境界という考え方を知ってから、テーブル単位の分割案に対して分散モノリスになりかねないと根拠を持って反論できるようになった。

印象に残っているのは、注文処理を切り出した直後に在庫更新サービスが落ち、注文だけ確定して在庫が減らない不整合が起きた出来事だ。当時はサーガという言葉すら知らず、担当者が手作業でデータを補正して終わらせた。読後に振り返れば、あれは補償トランザクションが必要な場面そのものだった。以来、サービスをまたぐ処理では「途中で失敗したら何を打ち消すか」を先に決めている。

CQRSとイベントソーシングの組み合わせは、自分たちの規模では過剰だと感じて見送った。契約テストも採用したかったが、テストダブルやDockerでのプロセス外テスト基盤づくりが重く、チームへの定着までは至っていない。

DevBookPath のマップで確認する

この本の学習パス上の位置づけ・前後の読書順は、DevBookPath のグラフで辿れます。

👉 バックエンドの地図を見る

📖 Amazon で購入する


本記事のリンクには Amazon アソシエイト等の広告が含まれる場合があります。リンク経由の購入で運営者に紹介料が支払われることがあります。

この記事を共有

この地図を共有