service-decomposition について
システムを独立してデプロイできるサービスに分割するか、境界や通信方式をどう決めるかを支援するスキルです。モノリス、モジュラーモノリス、マイクロサービスの比較に加え、分割後の障害や運用への影響も扱います。
主な機能
- 01モノリスとマイクロサービスの評価
- 02ビジネス機能に基づく境界設定
- 03同期・非同期通信の選択
- 04ゲートウェイ、サービス検出、メッシュの比較
- 05サービス間の障害リスク確認
活用シーン
- 01独立してデプロイするサービスの追加を検討
- 02拡張要件が異なるコンポーネントの分割
- 03サービス間通信と検出の計画
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ proyecto26/ system-design-skills --skill service-decompositionインストール後、Claude Code で/service-decompositionを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/deep-dive.mdreferences/providers/aws.mdazure.mdgcp.mdgeneric.md詳細
翻訳後に原文が更新されています。最新の内容は原文をご確認ください。
サービス分割
システムをデプロイ可能なサービスにどのように分割するか、そもそも分割するかどうか、そしてそれらのサービスがどのように互いを見つけて呼び出すかを決めます。これは設計の「アプリケーション層」であり、エッジ(dns/load-balancing/content-delivery)とデータ層の間に位置します。粒度を誤ることは、どちらの方向であっても分散システムにおいて非常に高くつく間違いの一つです。
落とし穴は両方向にあります。巨大なサービスが一つだけでは、チームやコンポーネントを独立してスケールできません。一方、小さなサービスが大量にあると、ネットワークホップ、部分的な障害、デバッグ不能なサービス横断トレースに追われることになります。重要なのはサービス数を最大化することではなく、この規模のこのシステムに合った最適なバランスを見つけることです。
どのような場合に検討するか
二つ目のサービスを検討している場合、チームが独立してデプロイする必要がある場合、ある部分のスケーリング特性が他と大きく異なる場合、または既存システムの「おしゃべりが多すぎる」/変更しにくい場合です。また、誰かが既定の選択肢として「マイクロサービス」を提案した場合も該当します。
検討すべきでない場合
新製品、小規模チーム、またはまだ実証されていないドメインの場合は、まずモノリス(またはモジュラーモノリス)から始め、実際の境界と明確な理由が現れてから分割します。早すぎる分割は、まだ抱えていない問題を解決するために、分散システムのコスト(ネットワーク障害、結果整合性、運用)を招きます(YAGNI、GUIDE #7)。必要とするサービスができるまでは、ゲートウェイ/メッシュ/ディスカバリー層を追加しないでください。
まず確認すること
- チームとデプロイの独立性 — 各部分を別々のスケジュール/担当者でリリースする必要がありますか?
- スケールの差 — あるコンポーネントに、他のコンポーネントの100倍のリソースが必要ですか?
- 結合度 — どの部分が一緒に変更される(まとめるべき)か、どの部分が別々に進化するか?
- レイテンシ予算 — プロセス内の呼び出しのうち、ネットワークホップになるのは何回ですか?
- 境界をまたぐ整合性 — サービス間の結果整合性を許容できる分割ですか?(→
consistency-coordination)
選択肢
- モノリス — デプロイ可能な単位が一つです。適している場合:新規/小規模、迅速な反復、モジュール間の強いトランザクション、一つのチーム。
- モジュラーモノリス — デプロイ可能な単位は一つで、内部モジュールの境界が明確に保たれています。適している場合:ネットワークコストをかけずに明確な境界を設けたい場合。「後で分割するかもしれない」場合の最適な既定の選択肢です。
- マイクロサービス — ビジネスケイパビリティ/境界づけられたコンテキストごとに分割された、小規模なデプロイ可能単位が複数あります。適している場合:独立したデプロイ/スケーリング/所有権によって、分散システムのコストに見合う実質的な利点が得られる場合。
- 通信スタイル — 各境界について、同期(REST/gRPC、リクエスト/レスポンス。単純ですが可用性が結合します)か、非同期(疎結合ですが結果整合性になります)かだけを決めます。この項目で決めるのは、境界ごとの同期か非同期かです。非同期の仕組み自体は扱いません。境界を非同期にする場合は、
messaging-streamingを呼び出し、安全性を確保する配信保証、順序付け、バックプレッシャー、DLQのセマンティクスを検討してください。失敗時の動作を確認せず、「すぐに回答する必要がない」という一行のルールだけで非同期を選ばないでください。ほとんどのシステムは両者を組み合わせます。 - サービス層のエッジ — APIゲートウェイ/BFF(認証、ルーティング、レート制限、集約を担う単一の入口)を設けるか、直接公開するか。
- 相互の検出方法 — サービスディスカバリー(レジストリ:DNSベース、またはetcd/Consul/ZooKeeper)や、任意でサービスメッシュ(mTLS、リトライ、トラフィック制御のためのサイドカー)を使うか、ライブラリレベルのクライアントを使うか。
トレードオフ
| 選択肢 | 解決できること | 悪化すること | 変更するタイミング |
|---|---|---|---|
| モノリス | シンプルさ、プロセス内呼び出し、トランザクション/デバッグの容易さ | デプロイ/スケーリングが密結合になる、1チームがボトルネックになる、影響範囲が広がる | チームやスケールの特性が異なってきたら → モジュラーモノリス → 境界を切り出す |
| モジュラーモノリス | 明確な境界、ネットワークコストなし、後から分割できる選択肢 | 依然としてデプロイは1つ、モジュールをクリーンに保つには規律が必要 | モジュールに独立したデプロイ/スケーリングが必要になったら → サービスとして切り出す |
| マイクロサービス | 機能ごとの独立したデプロイ/スケーリング/所有権 | ネットワーク障害、結果整合性、分散デバッグ、運用 | 調整/レイテンシのコストが独立性のメリットを上回ったら → 統合する |
| 同期通信 | シンプルなメンタルモデル、即時の結果 | 可用性が連動する(呼び出し先が機能しないと呼び出し元も失敗する)、レイテンシが積み重なる | 呼び出しに即時の応答が不要なら → 非同期(→ messaging-streaming) |
| API ゲートウェイ/BFF | 認証/ルーティング/レート制限/集約の窓口を一本化 | 新たな層と、SPOF/ボトルネックになる可能性、ミニモノリス化する可能性 | ビジネスロジックが蓄積してきたら → ロジックをサービスに戻す |
| サービスメッシュ | アプリケーションを変更せず、統一された mTLS/リトライ/可観測性を実現 | 実際の運用コストとレイテンシのオーバーヘッド(サイドカー) | サービスが少数なら → ライブラリ/ゲートウェイで十分 |
負荷がかかったときの挙動
- おしゃべりなサービス/ファンアウト: 1つのユーザーリクエストが N 個の同期内部
呼び出しになり、テールレイテンシが積み重なり、単一の遅い依存先が呼び出しの連鎖を停滞させます。
軽減策: 境界をより大きくする、バッチ処理、今すぐ応答が不要な場合は
非同期にする、サーキットブレーカーを使う(→
resilience-failure)。 - 分散トランザクションの問題: サービスをまたぐ書き込みを1つの ACID
トランザクションにすることはできません。軽減策: Saga/Outbox を使うか、データを1つのサービス内に保ち、
トランザクションをローカルに保ちます(→
consistency-coordination)。 - メッシュ全体でのリトライストーム: 単純なリトライは過負荷を連鎖障害に拡大させます。
軽減策: バックオフ+ジッター、予算、サーキットブレーカー(→
resilience-failure)。 - デバッグ可能性の崩壊: 相関 ID/トレーシングがないと、
6つのサービスをまたぐ障害を把握できません。軽減策: 初日から分散トレーシング+相関
ID を導入します(→
observability、distributed-logging)。 - ゲートウェイ/ディスカバリーの SPOF 化: 窓口またはレジストリが停止すると、すべてが 停止します。軽減策: 冗長化、ディスカバリー情報のクライアント側キャッシュ、ヘルスチェック。
適用方法
- 推進要因を明確にする — 独立したデプロイが必要ですか? スケールに差がありますか? チームの 所有権が異なりますか? いずれも現実的な要件でなければ、そこで止めましょう。(モジュラー)モノリスが適しています。
- 要件を満たす最もシンプルな構成をデフォルトにする — モノリス → モジュラーモノリス → 明確な理由がある境界を1つだけ切り出します。「すべてをサービスにする」わけではありません。
- ビジネス機能/境界づけられたコンテキストで境界を分ける。データと、それを所有する ロジックを一緒に保ちます(サービス間トランザクションを最小限にします)。
- 呼び出しごとに通信方式を選ぶ — 呼び出し元が即時の応答を必要とする場合に限り同期にし、それ以外は非同期にします(→
messaging-streaming)。 - 必要な場合にのみ窓口とディスカバリーを追加する — 認証/ルーティング/集約にはゲートウェイ/BFF を、 サービス数が増えて静的な接続設定が難しくなったらディスカバリー/メッシュを使います。
- 境界をストレステストする — 決定する前に、頻繁な呼び出し、サービス間トランザクション、リトライの 連鎖、トレーシングを確認します。
やるべきこと、やってはいけないこと
やるべきこと
- モノリス/モジュラーモノリスから始め、現実的な推進要因が現れた場合にのみ境界を切り出します。
- ビジネス機能ごとに分割し、サービスが自身のデータを所有するようにします(トランザクションをローカルに保ちます)。
- サービス間のすべての呼び出しに、最初から相関 ID とトレーシングを付与します。
- 適切な規模にします。数が少なく境界が明確なサービスのほうが、小さくて頻繁に通信するサービスを多数作るより優れています。
やってはいけないこと
- デフォルトでマイクロサービスを選んだり、履歴書のために選んだりしないでください(GUIDE #7)。
- 同じトランザクション内で別のサービスのデータを必要とする書き込みを行うサービスを作らないでください。
- API ゲートウェイにビジネスロジックを蓄積させ、隠れたモノリスにしないでください。
- サービスが少数の場合はサービスメッシュを追加しないでください。オーバーヘッドがメリットを上回ります。
重要な数値
同期ホップごとに、同一データセンター内のラウンドトリップ(約0.5 ms)に加えて、呼び出し先自身の処理が発生します。同期ホップが10回でも、ネットワークの遅延は約5 msにすぎません。実際のコストは、積み重なるp99/シリアライズ/キューイング/再試行によるテール遅延です。ホップごとに遅い依存先に当たる可能性が高まるため、エンドツーエンドのp99は平均よりもはるかに速く悪化します。分割する前に、明示的なp99予算を設定したうえで、呼び出しグラフの深さとホップごとのp99(ネットワークだけでなく)を見積もってください。→ back-of-the-envelope。
インターフェースの概要
サービス境界は契約です。具体的には、所有するデータ(各エンティティの信頼できる情報源となるサービス)、公開するAPI(→ api-design)、発行するイベント(→ messaging-streaming)です。サービスの箱を描く前に、「ユーザーレコードはどのサービスが所有するのか、注文はどのサービスが所有するのか」を書き出してください。境界を越えて変更可能なデータを共有するのは、分解における最大の危険信号です。
プロバイダーの選択
既定では、上記の汎用的な手順を使ってください。ユーザーがクラウドを指定した場合は、マネージドゲートウェイ/ディスカバリー/メッシュの対応付け、制限、トレードオフについて、references/providers/<provider>.md を確認してください。そのプロバイダー向けのファイルがない場合は、汎用的な手順が答えになります。
図
サービス層(ゲートウェイ → サービス → 各サービスのデータ。同期と非同期のエッジ、および信頼境界を含む)を可視化するには、プラグイン内蔵の architecture-diagram スキルを使ってください。
関連する構成要素
api-design— これと組み合わせて使います。分解によって境界を定め、api-designで各サービスの契約を定義します。messaging-streaming— サービス間の非同期/イベント駆動型通信(同期結合の代替)には、これと組み合わせて使います。consistency-coordination— サービス間の一貫性の扱い(Saga/2PC)と、サービスディスカバリーの背景にある調整理論(リーダー選出、etcd/Consul/ZooKeeper など)を担当します。ここにリンクし、内容を重ねて説明しないでください。resilience-failure— これを前提とします。サーキットブレーカー、タイムアウト、バルクヘッドによって、通信の多いメッシュで障害が連鎖するのを防ぎます。observability+distributed-logging— これに情報を提供します。トレーシングと相関 ID によって、複数サービスにまたがるリクエストをデバッグできます。scaling-evolution— これに情報を提供します。サービスの切り出しは、「境界を分割する」段階でのスケーリング施策です。system-design— オーケストレーターです。
参考資料
references/deep-dive.md— 境界づけられたコンテキストと分割点の見つけ方、モノリスからのストラングラーフィグ移行、ゲートウェイとBFFとメッシュの違い、同期/非同期を選ぶ際の詳細、サービス間書き込みにおけるSaga/outbox、粒度に関するアンチパターン(ナノサービス、分散モノリス、共有データベース)。references/providers/{generic,aws,azure,gcp}.md— 各環境におけるゲートウェイ/サービスディスカバリー/メッシュのサービス対応付け、制限、落とし穴。