ストーリー
サービス分割のアプローチ
Strangler Fig パターン(詳細)
graph TD
subgraph P1["Phase 1: ファサード追加"]
GW1["API Gateway\nリクエストをルーティング"] --> NewSvc["新サービス\n通知"]
GW1 --> Mono1["モノリス\n残りの機能"]
end
subgraph P2["Phase 2: 段階的移行"]
GW2["API Gateway"] --> N2["通知"]
GW2 --> O2["注文"]
GW2 --> P2a["決済"]
GW2 --> Mono2["モノリス\n縮小中"]
end
subgraph P3["Phase 3: 完了"]
GW3["API Gateway"] --> N3["通知"]
GW3 --> O3["注文"]
GW3 --> P3a["決済"]
GW3 --> I3["在庫"]
GW3 --> C3["顧客"]
end
style P1 fill:#f3f4f6,stroke:#9ca3af,color:#374151
style P2 fill:#fef3c7,stroke:#d97706,color:#92400e
style P3 fill:#d1fae5,stroke:#059669,color:#065f46
style GW1 fill:#f3e8ff,stroke:#7c3aed,color:#5b21b6
style GW2 fill:#f3e8ff,stroke:#7c3aed,color:#5b21b6
style GW3 fill:#f3e8ff,stroke:#7c3aed,color:#5b21b6
style NewSvc fill:#d1fae5,stroke:#059669,color:#065f46
style Mono1 fill:#fee2e2,stroke:#dc2626,color:#991b1b
style Mono2 fill:#fef3c7,stroke:#d97706,color:#92400e
style N2 fill:#d1fae5,stroke:#059669,color:#065f46
style O2 fill:#d1fae5,stroke:#059669,color:#065f46
style P2a fill:#d1fae5,stroke:#059669,color:#065f46
style N3 fill:#d1fae5,stroke:#059669,color:#065f46
style O3 fill:#d1fae5,stroke:#059669,color:#065f46
style P3a fill:#d1fae5,stroke:#059669,color:#065f46
style I3 fill:#d1fae5,stroke:#059669,color:#065f46
style C3 fill:#d1fae5,stroke:#059669,color:#065f46
分割順序の決め方
| 優先度 | 基準 | 理由 |
|---|---|---|
| 1 | 変更頻度が高いモジュール | 独立デプロイの効果が最大 |
| 2 | 依存が少ないモジュール | 分離が容易でリスクが低い |
| 3 | チームが明確なモジュール | 所有権が自然に決まる |
| 4 | パフォーマンス要件が異なるモジュール | 独立スケーリングの恩恵 |
データベース分割戦略
パターン1: Database per Service
graph TD
subgraph Before["Before: 共有DB"]
SharedDB["共有 PostgreSQL"]
SharedDB --> T1["orders"]
SharedDB --> T2["products"]
SharedDB --> T3["users"]
end
subgraph After["After: DB per Service"]
DB1["Order DB\nPostgres"]
DB2["Product DB\nPostgres"]
DB3["User DB\nPostgres"]
end
style Before fill:#fee2e2,stroke:#dc2626,color:#991b1b
style After fill:#d1fae5,stroke:#059669,color:#065f46
style SharedDB fill:#fee2e2,stroke:#dc2626,color:#991b1b
style T1 fill:#f3f4f6,stroke:#9ca3af,color:#374151
style T2 fill:#f3f4f6,stroke:#9ca3af,color:#374151
style T3 fill:#f3f4f6,stroke:#9ca3af,color:#374151
style DB1 fill:#dbeafe,stroke:#2563eb,color:#1e40af
style DB2 fill:#d1fae5,stroke:#059669,color:#065f46
style DB3 fill:#f3e8ff,stroke:#7c3aed,color:#5b21b6
パターン2: 段階的分離(推奨)
graph TD
S1["Step 1\nSchema分離(同一DB内)"] --> S2["Step 2\nView/Synonym で互換維持"]
S2 --> S3["Step 3\nAPI経由に切り替え"]
S3 --> S4["Step 4\n物理DB分離"]
S1 -.- D1["PostgreSQL内で\norder / product / user\nスキーマを分離"]
S2 -.- D2["orders_view →\nproduct_schema.products\nREAD互換を維持"]
S3 -.- D3["Order Service\n--HTTP/gRPC-->\nProduct Service"]
S4 -.- D4["各サービス専用の\nDBインスタンスに分離"]
style S1 fill:#dbeafe,stroke:#2563eb,color:#1e40af
style S2 fill:#dbeafe,stroke:#2563eb,color:#1e40af
style S3 fill:#fef3c7,stroke:#d97706,color:#92400e
style S4 fill:#d1fae5,stroke:#059669,color:#065f46
style D1 fill:#f3f4f6,stroke:#9ca3af,color:#374151
style D2 fill:#f3f4f6,stroke:#9ca3af,color:#374151
style D3 fill:#f3f4f6,stroke:#9ca3af,color:#374151
style D4 fill:#f3f4f6,stroke:#9ca3af,color:#374151
データ整合性の課題
// モノリス時代: JOINで簡単に取得
// SELECT o.*, p.name FROM orders o JOIN products p ON o.product_id = p.id
// マイクロサービス: API Composition パターン
class OrderDetailComposer {
async getOrderWithProducts(orderId: string): Promise<OrderDetail> {
// 並行して2つのサービスからデータ取得
const [order, products] = await Promise.all([
this.orderService.getOrder(orderId),
this.productService.getProducts(order.items.map((i) => i.productId)),
]);
return {
...order,
items: order.items.map((item) => ({
...item,
product: products.find((p) => p.id === item.productId),
})),
};
}
}
移行中のデータ同期
Change Data Capture (CDC)
graph LR
MDB["モノリス<br/>DB"] -->|WAL| DEB["Debezium<br/>(CDC)"] -->|Kafka| NDB["新サービス<br/>DB"]
classDef db fill:#e8f4fd,stroke:#2196f3,color:#333
classDef mid fill:#fff3cd,stroke:#f0ad4e,color:#333
class MDB,NDB db
class DEB mid
旧DBの変更をリアルタイムに新サービスのDBへ反映し、移行期間中のデータ整合性を維持します。
Dual Write の危険性
❌ 避けるべき: Dual Write
Service → Write to DB A → Write to DB B
(成功) (失敗したら?)
✅ 推奨: CDC or Outbox パターン
Service → Write to DB A → CDC → DB B
(1箇所書き込み) (自動同期)
まとめ
| ポイント | 内容 |
|---|---|
| Strangler Fig | 段階的にモノリスを置き換える |
| 分割順序 | 変更頻度・依存度・チーム構造で判断 |
| DB分離 | Schema分離→View→API→物理分離の順 |
| データ同期 | CDCで移行期間中の整合性を維持 |
チェックリスト
- Strangler Fig パターンのフェーズを説明できる
- サービス分割の優先順位を判断できる
- DB分離の段階的アプローチを理解した
- CDC によるデータ同期の仕組みを理解した
次のステップへ
次はサービス間のAPI契約設計を学びます。
推定読了時間: 40分