ストーリー
佐
佐藤CTO
分散システムには避けられない物理法則がある
佐
佐藤CTO
CAP定理、ネットワーク分断、部分障害 — これらを理解しないまま設計すると、本番で痛い目に遭う
CAP定理
分散システムでは以下の3つを同時に満たすことはできません:
| 特性 | 説明 |
|---|
| Consistency | 全ノードが同時に同じデータを返す |
| Availability | 全リクエストが応答を返す(エラーでない) |
| Partition Tolerance | ネットワーク分断時も動作を続ける |
現実の選択
ネットワーク分断(P)は避けられないため、実質的にCかAの選択になります:
ネットワーク分断発生時:
CP選択(整合性優先):
Client → Node A [データ更新]
Node A --✕-- Node B [分断]
→ Node B はエラーを返す(可用性を犠牲)
AP選択(可用性優先):
Client → Node A [データ更新]
Node A --✕-- Node B [分断]
→ Node B は古いデータを返す(整合性を犠牲)
| サービス例 | 選択 | 理由 |
|---|
| 決済処理 | CP | 二重課金は許されない |
| 商品カタログ | AP | 古い在庫表示は許容 |
| ユーザーセッション | AP | ログアウト遅延は許容 |
| 在庫引当 | CP | 在庫超過は許されない |
ACID vs BASE
| 特性 | ACID(モノリス) | BASE(マイクロサービス) |
|---|
| 原子性 | 全て成功 or 全て失敗 | Basically Available |
| 一貫性 | 常に整合 | Soft state |
| 分離性 | トランザクション分離 | Eventually consistent |
| 永続性 | コミット=永続 | - |
// ACID: 単一DBトランザクション
await db.transaction(async (tx) => {
const order = await tx.insert(orders).values(orderData);
await tx.update(inventory).set({ stock: stock - quantity });
await tx.insert(payments).values(paymentData);
// 全て原子的に成功 or 失敗
});
// BASE: 結果整合性
// 1. 注文サービスで注文作成(ローカルトランザクション)
await orderDb.insert(orders).values(orderData);
// 2. イベント発行 → 在庫サービスが非同期で処理
await kafka.publish('order.confirmed', orderEvent);
// 3. 最終的に整合する(すぐには整合しない)
整合性モデル
| モデル | 保証 | レイテンシ |
|---|
| 強整合性 | 書き込み直後に全ノードで読める | 高 |
| 因果整合性 | 因果関係のある操作は順序保証 | 中 |
| 結果整合性 | いずれ全ノードで同じ値になる | 低 |
| 読み取り一貫性 | 自分の書き込みは必ず読める | 低〜中 |
実装パターン
// 読み取り一貫性(Read Your Own Writes)
class OrderService {
async createAndRead(orderData: OrderInput): Promise<Order> {
const order = await this.writeDb.create(orderData);
// 自分が書いたデータはwriteDb(Primary)から読む
return await this.writeDb.findById(order.id);
// 他人のデータはreadDb(Replica)から読んでOK
}
}
2PC(Two-Phase Commit)の限界
Phase 1: Prepare
Coordinator → Participant A: "コミットできる?" → "YES"
Coordinator → Participant B: "コミットできる?" → "YES"
Phase 2: Commit
Coordinator → Participant A: "コミットせよ" → Done
Coordinator → Participant B: "コミットせよ" → Done
| 問題 | 説明 |
|---|
| ブロッキング | Prepare後にCoordinatorが落ちると全Participant が待ち状態 |
| 単一障害点 | Coordinator障害で全体停止 |
| レイテンシ | 2フェーズの同期通信でレスポンス遅延 |
| スケーラビリティ | 参加者増加で性能劣化 |
結論: マイクロサービスでは2PCは推奨されない。代わりにSagaパターンを使用する。
まとめ
| ポイント | 内容 |
|---|
| CAP定理 | P は必須、C/A のトレードオフ |
| BASE | 結果整合性を受け入れる設計 |
| 整合性モデル | 要件に応じて使い分け |
| 2PC の限界 | ブロッキング・単一障害点の問題 |
チェックリスト
次のステップへ
次は Saga パターンと 2PC の詳細比較を学びます。
推定読了時間: 40分