DIVE

Part 5: ネットワーク・SRE

第 15 章

CAP定理 — 分散システムが直面する『選べない選択』

前章まで、私たちは通信を信頼でき、秘匿されたものにした。だが現代のサービスは、1台のサーバーでは動かない。障害に備え、負荷を分散するため、データは複数のマシンに複製(レプリケーション)される。

ここで、避けようのない哲学的難問が生まれる。複数のコピーが存在するとき、それらは本当に「同じ」だと言い切れるのか? そして、マシン間の通信が切れたとき——「正しさ」と「動き続けること」の、どちらを取るのか。 この選べない選択を定式化したのがCAP定理だ。この章では、分散システムの宿命と、それに立ち向かう思想を解く。


3つのうち、2つしか選べない — 歴史の必然

分散システムには、3つの望ましい性質がある。CAP定理(2000年、Eric Brewerが提唱、後に証明)は、この3つを同時にすべて満たすことはできないと述べる。

性質意味
C: 一貫性(Consistency)どのノードに聞いても、常に最新の同じ答えが返る
A: 可用性(Availability)生きているノードは、必ず応答を返す(待たせない)
P: 分断耐性(Partition tolerance)ネットワークが分断されても、システムは動き続ける

ここで決定的な事実がある。分散システムにおいて、ネットワーク分断(P)は「選択肢」ではなく「避けられない現実」だ。ケーブルは切れ、ルーターは落ち、パケットは失われる(第13章)。だから実質的な選択は、分断が起きたとき、C と A のどちらを諦めるかに絞られる。

ネットワーク分断が起きたとき:C (一貫性)かA (可用性)の二択\text{ネットワーク分断が起きたとき}: \quad \boxed{C\ \text{(一貫性)}} \quad \text{か} \quad \boxed{A\ \text{(可用性)}} \quad \text{の二択}

厨房のアナロジー — 2店舗の予約台帳が食い違う

あなたのレストランが、本店と支店の2店舗を持つとする。予約台帳(データ)は両店で共有し、常に同じ内容に保ちたい(一貫性)。普段は電話で「今この予約が入った」と即座に同期している。

ある日、2店舗をつなぐ電話が不通になった(ネットワーク分断)。ここに客が来て「今夜のディナーを予約したい」と言う。あなたは二択を迫られる。

私が飲食店で店舗間の予約管理に関わったとき、まさにこのジレンマがあった。「確実さを取って断るか、機会損失を避けて受けるか」。どちらが正解かは、ビジネスの性質による。CAP定理は、この判断が技術ではなく事業上の選択だと教えてくれる。

       通常時: C も A も両立できる
  ┌─────┐  同期  ┌─────┐
  │本店 │◀──────▶│支店 │   台帳は常に一致
  └─────┘        └─────┘

       分断時(電話不通): C か A の二択を迫られる
  ┌─────┐   ╳    ┌─────┐
  │本店 │──断線──│支店 │
  └─────┘        └─────┘
   CP: 「確認できないので断る」(正しいが止まる)
   AP: 「とりあえず受ける」(動くが食い違いうる)

CP型とAP型 — 実システムの選択

現実のデータストアは、この思想の違いで design が分かれている。

CP型(一貫性優先): 分断時、正しさを保証できない側は応答を止める。「間違った答えを返すくらいなら、答えない」。

AP型(可用性優先): 分断時も応答を返し続ける。食い違いは後で解決する(結果整合性, Eventual Consistency)。

CP型: 「正しくないなら答えない」
   分断発生 → 少数派ノードは応答停止 → 復旧後に整合
   (銀行残高: 食い違いは絶対NG)

AP型: 「とりあえず答える、後で直す」
   分断発生 → 各ノードが応答継続 → 復旧後に矛盾を解決(結果整合性)
   (SNSいいね数: 一時的なズレは許容)

第11章のWAL(ログを先に書く)を思い出してほしい。分散システムのレプリケーションは、突き詰めれば「このログを他ノードにどう伝え、どう合意するか」という問題だ。「過半数のノードが合意したら確定」とする分散合意アルゴリズム(Paxos, Raft)は、CP型システムの心臓部になっている。

なぜ「結果整合性」で許されるのか

AP型の「結果整合性」は手抜きではなく、意図的な設計だ。多くのユースケースでは、厳密な一貫性より、止まらないことの方が価値が高い。ショッピングサイトが「一貫性確認中」で真っ白になるより、多少古い在庫数でも表示され続ける方が、売上を守れる。CAP定理の教えは、「万能はない。要件に応じてトレードオフを選べ」ということだ。


PACELC — CAPの先へ(補足)

CAP定理には続きがある。PACELCという拡張だ。CAPは「分断(P)が起きたとき A か C か」だけを語るが、現実には分断していない平常時(E: Else)にもトレードオフがある——低遅延(L: Latency)か 一貫性(C)かだ。

分断時(P)は A か C か。平常時(E)は L(レイテンシ)か C(一貫性)か。

全ノードに書き込みが行き渡るのを待てば一貫性は上がるが、応答は遅くなる。待たずに返せば速いが、一瞬古いデータを返しうる。「強い一貫性はレイテンシと引き換え」という、現場のエンジニアが日々直面する感覚を、PACELCは的確に言い当てている。


カオスエンジニアリング — あえて壊して強くする

CAP定理は「障害は必ず起きる」と教える。ならば、障害が起きてから慌てるのではなく、平常時にわざと障害を起こして、耐性を確かめておけばいい。この逆転の発想がカオスエンジニアリングだ。

Netflixが2011年に生んだ Chaos Monkey が象徴的だ。これは本番環境で、ランダムにサーバーを停止させるツールだ。正気の沙汰に聞こえるが、思想は深い。

「いつか必ず落ちるなら、都合のいい昼間に、監視された状態で、わざと落とす。」

深夜に予期せず落ちて大障害になるより、エンジニアが見ている日中に意図的に落とし、「本当に自動復旧するか」「冗長化は機能するか」を検証する。障害を制御された実験に変えるのだ。

カオスエンジニアリングは、科学の実験と同じ手順を踏む。

① 定常状態の定義: 「正常」を計測可能な指標で定義
     (例: 注文成功率 99.9%、レイテンシ p99 < 300ms)
        │
        ▼
② 仮説: 「サーバーを1台落としても、指標は維持されるはず」
        │
        ▼
③ 実験: 本番(or 近い環境)で、あえて障害を注入
     (インスタンス停止 / 遅延注入 / パケットロス / 依存サービス切断)
        │
        ▼
④ 検証: 指標は維持されたか? → 崩れたら、それが「隠れた弱点」
        │
        ▼
⑤ 改善して再実験。爆発半径(影響範囲)は小さく始め、徐々に広げる

ここでエラーバジェットという考え方が効く。「100%の稼働率」は幻想だ(CAP定理が示す通り)。そこでSREは、たとえば「99.9%の可用性」を目標に定める。すると許容される停止時間(エラーバジェット)が計算できる:

許容停止時間(月)=(1−0.999)×30日×24h×60min≈43 分/月\text{許容停止時間(月)} = (1 - 0.999) \times 30\text{日} \times 24\text{h} \times 60\text{min} \approx 43\ \text{分/月}

この43分を「使ってよい予算」とみなし、その範囲であえてリスクを取って実験や機能追加を行う。可用性を神格化せず、工学的に管理する——これがSRE(Site Reliability Engineering)の中核思想だ。


まとめ — 「おまじない」の消し方

  1. CAPは選べない選択:C・A・P の3つは同時に満たせない。分断(P)は不可避なので、実質は C か A の二択
  2. CP型 vs AP型:正しさを守って止まるか(銀行)、動き続けて後で整合するか(SNS)。事業要件が決める
  3. 結果整合性は設計:「止まらないこと」に価値がある領域では、一時的なズレを意図的に許容する
  4. カオスエンジニアリング:障害は必ず起きる。ならば平常時にあえて壊し、制御された実験で弱点を暴く
  5. エラーバジェット:100%は幻想。許容停止時間を予算とみなし、可用性を工学的に管理する

「なぜ完璧に一貫したシステムは作れないのか」「なぜNetflixはわざとサーバーを落とすのか」——その答えは、分散システムの宿命と、それを受け入れる思想にあった。これでPart 5——マシンとマシンの間の世界——を一巡した。

ここまでの旅は「どう動かすか」の話だった。次のPart 6からは、視点を「大量の計算をどう速くするか」、そしてAIを支える数学へ移す。まずは、数千のコアで押し切る怪物——GPUの超並列——の物理へ。


「完璧なシステムは存在しない。優れたエンジニアと平凡なエンジニアを分けるのは、障害を無くそうとするか、障害と共に生きる術を設計するかの違いだ。壊れることを前提に作られたものだけが、本当に壊れにくい。」