Eric BrewerのCAP思考:なぜ分散システムはトレードオフを迫られるのか
Eric BrewerのCAP定理を実用的なメンタルモデルとして学ぶ:一貫性・可用性・分断耐性が分散システムの判断にどう影響するかを解説します。

なぜCAPが定番のメンタルモデルになったのか
同じデータを複数のマシンに保管すると、速度と耐障害性を得られます——しかし新たな問題も生じます:不一致です。二つのサーバが異なる更新を受け取り得るし、メッセージは遅延したり届かなかったり、ユーザーはどのレプリカに当たるかで違う答えを読むかもしれません。CAPが広まったのは、エンジニアがそのややこしい現実を曖昧さなく語れる枠組みを与えたからです。
エリック・ブルーワー(Eric Brewer)は2000年に、故障下のレプリケーションされたシステムについての実用的な主張としてこのコアアイデアを提示しました。それは現場でチームが既に経験していたものと一致したため急速に広まりました:分散システムは単に停止するだけでなく、分裂することで故障するのです。
CAPは機能チェックリストではなく故障を見るレンズ
CAPが最も有用なのは問題が発生したとき、特にネットワークが正常に振る舞わないときです。正常な日には、多くのシステムが十分に一貫して見え、十分に利用可能に見えるかもしれません。試練は、マシンが確実に通信できないときで、その間に読み書きをどう扱うかを決めなければなりません。
この視点がCAPを定番にした理由です:CAPはベストプラクティスを論じるのではなく、具体的な問いを突き付けます——分断時に何を犠牲にしますか?
この記事で判断できるようになること
この記事を読み終えるころには、次ができるようになっているはずです:
- 本当にCAPの状況(レプリケーション+通信断の可能性)に直面しているかを見分ける。
- レプリカが合意できないときに、一貫性(全員が同じ真実を見る)を優先するか、可用性(システムが応答し続ける)を優先するかを意図的に選ぶ。
- その選択をプロダクトへの影響(ユーザーが体験すること、表示するエラー、分断が治った後に必要な修復)に結び付ける。
CAPが残り続けるのは、「分散が難しい」を意思決定に落とし込めるからです。
セットアップ:レプリケーションと不一致の問題
分散システムとは平たく言えば「多くのコンピュータが一つのように振る舞おうとすること」です。複数のサーバを別々のラックやリージョン、クラウドのゾーンに置くかもしれませんが、ユーザーから見ればそれは「アプリ」や「データベース」です。
なぜデータをレプリケートするのか
実稼働スケールでその共有システムを動かすには、普通はレプリケーションします:同じデータの複数コピーを別のマシンに保持します。
レプリケーションが採用される実用的な理由は三つです:
- スケール: より多くのマシンで多くのトラフィックを裁ける
- パフォーマンス: ユーザーが近いコピーにアクセスできればレイテンシが下がる
- 信頼性: あるマシンが死んでも別のコピーがサービスを継続できる
ここまではレプリケーションは明らかに有利に見えます。しかし落とし穴は、レプリケーションが新しい仕事を生むことです:すべてのコピーを合意状態に保つことです。
中核の緊張:コピーは不一致になり得る
すべてのレプリカが常に瞬時に互いに通信できれば、更新を調整して整合を保てます。しかし現実のネットワークは完璧ではありません。メッセージは遅れる、失われる、失敗を回避する経路に迂回されることがあります。
通信が健全なとき、レプリカは通常更新を交換して同じ状態に収束します。しかし通信が切れる(たとえ一時的にでも)と、**二つのもっともらしい「真実」**が生まれることがあります。
例えば、ユーザーが配送先住所を変更したとします。レプリカAは更新を受け取り、レプリカBは受け取らない。今、システムは一見単純な問いに答えなければなりません:現時点の住所はどれか?
正常運用と障害時運用の違い
これは次の違いです:
- 正常運用: レプリカは調整できる;不一致は主にタイミングの問題
- 障害運用: あるレプリカ同士が通信できない;不一致は避けられない
CAP思考はまさにここから始まります:レプリケーションが存在すると、通信障害下の不一致は例外ではなく中心的な設計問題になるのです。
平易な言葉でのCAP:C、A、P
CAPは、システムが複数マシン(多くは複数のロケーション)に分散しているときに「ユーザーが実際に感じること」を扱うメンタルモデルです。良し悪しを判定するものではなく、管理すべき緊張関係を示します。
一貫性(C):最新の書き込みが見えるか?
一貫性は合意についてです。何かを更新したら、その後の読み取り(どこからでも)がその更新を反映するでしょうか?
ユーザー視点では「今変更したことが皆同じ新しい値として見える」か、「しばらくの間は一部の人が古い値を見ることがある」かの違いです。
可用性(A):そもそも応答が得られるか?
可用性はリクエスト(読み/書き)に成功結果で応答することを意味します。最速で返すという意味ではなく、「応答を拒絶しない」ことです。
トラブル時(サーバのダウンやネットワークの問題)でも、可用性を優先するシステムはリクエストを受け付け続けますが、データはやや古い可能性があります。
分割耐性(P):ノード間の通信ができないときにどうなるか?
パーティション(分断)はネットワークの分割で、マシンは稼働しているが一部間でメッセージが届かない(あるいは遅すぎて役に立たない)状況です。分散システムではこれを起こり得ないと扱うことはできません—分断が起きたときの振る舞いを定義しておく必要があります。
簡単な例:二つの店舗と在庫
同じ商品を販売する二つの小売店があり、「在庫カウントは1」で共有していると想像してください。顧客が店舗Aで最後の1つを買い、店舗Aは在庫 = 0と書き込んだ。同時にネットワーク分断で店舗Bにはその情報が届かない。
店舗Bが可用性を維持すれば、在庫のない商品を販売してしまう(分断中に販売を受け入れる)かもしれません。店舗Bが一貫性を強制すれば、最新在庫を確認できるまで販売を拒否する(分断中にサービスを拒否する)かもしれません。
分断とは何か(そして無視できない理由)
「分断」は単なる「インターネットが落ちた」ではありません。システムの一部同士が信頼して通信できないあらゆる状況です — 各部はまだ正常に動いている場合もあります。
レプリケートされたシステムでは、ノードは常にメッセージを交換しています:書き込み、確認応答、ハートビート、リーダー選出、読み取りリクエスト。そうしたメッセージが届かなくなる(あるいは遅すぎる)と、現実についての不一致が起きます:「その書き込みは実際に起きたのか?」「リーダーは誰か?」「ノードBは生きているか?」といった疑問です。
分断は通信障害である
通信障害はさまざまな不完全な形で現れます:
- リトライやタイムアウトを誘発するパケットロス
- 交通が長い迂回を取るかブラックホールになるルーティング問題
- 負荷で飽和したリンク(またはNIC)による長大な遅延
- 特定のポートや方向だけをブロックするファイアウォール/セキュリティグループの誤設定
- ノード同士が見つけられないDNSやサービスディスカバリの不具合
重要な点は:分断はたいてい劣化として現れ、明確なオン/オフの障害ではないことです。アプリから見ると「十分に遅い」は「落ちている」と区別が付かないことがあります。
大規模で分断は避けられない
マシンやネットワーク、リージョン、依存が増えれば増えるほど、通信が一時的に壊れる機会は増えます。個々のコンポーネントが信頼できても、全体としては依存関係とノード間の協調が多いために障害を経験します。
正確な故障確率は仮定する必要はなく、システムが十分長く稼働し十分なインフラにまたがれば分断は起きると受け入れることが重要です。
実務での「分断を許容する」とは
分断耐性とは、たとえノードが合意できず相手が見たものを確認できなくても分割中に稼働を続けられるように設計することです。これには選択が伴います:リクエストを受け付けて不一致を許す(可用性)か、いくつかのリクエストを止める/拒否して一貫性を守るか。
キーとなる瞬間:分断中に一貫性か可用性かを選ぶ
レプリケーションがあると分断は単に通信の切断です:システムの二つの部分がしばらくの間信頼して通信できない。レプリカは稼働を続け、ユーザーは操作を行い、サービスはリクエストを受ける——しかしレプリカ同士は最新の真実で合意できない。
これがCAPの緊張の一文でのまとめです:分断が発生したら、一貫性(C)を優先するか可用性(A)を優先するかを選ばなければならない。 同時に両方を得ることはできません。
一貫性(C)を選ぶ場合
「応答性より正確さを取る」と宣言しているわけです。リクエストがすべてのレプリカを同期させることを確認できない場合、失敗させるか待つ必要があります。
実際の影響:一部のユーザーはエラーやタイムアウト、あるいは「再試行してください」といったメッセージを見ることが多くなります。二重請求を避ける、席を重複して確保しない、など取り返しのつかない誤りを避けたい場面で使われます。
可用性(A)を選ぶ場合
「ブロックするより応答する方を選ぶ」と宣言しています。分断のそれぞれの側は、調整できなくてもリクエストを受け続けます。
実際の影響:ユーザーは成功応答を得ますが、読み取るデータは古い可能性があり、同時更新は競合するかもしれません。後で和解(マージルール、最終書き込み勝ち、手動レビューなど)に頼ることになります。
操作ごとに選択を変えられる
これは常にグローバルな設定である必要はありません。多くのプロダクトは戦略を混ぜます:
- 読み取りと書き込みを分ける: 読み取りは可用性優先、書き込みはより厳格に
- 重要/非重要の操作で差をつける: 金銭・アイデンティティ・在庫は一貫性重視、フィード・分析・「いいね」などは可用性重視
重要なのは操作ごとに「今ユーザーをブロックすること」と「後で矛盾を直すこと」のどちらがより悪いかを決めることです。
よくある誤解:「二つを選べ」スローガンを超えて
「二つ選べ(pick two)」というスローガンは覚えやすいですが、しばしば誤解を生みます。CAPは、分断が起きたときに何が起こるかを扱います:分断中に分散システムは一貫した答えを返すのか、それともすべてのリクエストに対して可用性を維持するのか、ということです。
誤解1:「CとAを選んでおけば分断を避けられる」
現実の分散システムでは分断は無効化できません。マシン、ラック、ゾーン、リージョンにまたがればメッセージは遅延したり、失われたり、順序が入れ替わったりします。これらはソフトウェアから見ると「ノード同士が十分に協調できない」分断です。
物理ネットワークが健全でも、GCポーズ、ノイジーネイバー、DNSの一時不具合などが同じ効果を生みます。
誤解2:「分断は稀なエッジケースだ」
アプリケーションは「分断」をきれいな二値イベントとして経験するわけではありません。むしろレイテンシスパイクやタイムアウトとして経験します。リクエストが200msでタイムアウトするなら、そのパケットが201msで届いたのか全く届かなかったのかに関係なく、アプリは次にどうするかを決めなければなりません。遅い通信は壊れた通信と同じ振る舞いを示します。
誤解3:「システムはCPかAPのどちらかだ」
多くの実システムは設定や動作条件によって「ほぼ一貫性」または「ほぼ可用性」に見えます。タイムアウト、リトライ方針、クォーラムサイズ、「read-your-writes」オプションが振る舞いを変えます。通常条件下では強い一貫性に見えるデータベースも、ストレスやクロスリージョンの問題下ではリクエストを失敗させ始め(一貫性重視)あるいは古いデータを返し始める(可用性重視)ことがあります。
CAPは製品ラベルを貼るためのものではなく、不一致が発生したときにどんなトレードオフをしているかを理解するためのものです。
実際に選べる一貫性のオプション
CAPの議論は一貫性を二値化しがちですが、現実には複数の保証レベルがあり、不一致やネットワーク断時に異なるユーザー体験をもたらします。
強い一貫性(と障害時の代償)
強い一貫性(しばしば「線形化可能」)は、書き込みが確認されたらその後のすべての読み取りがその書き込みを返すことを意味します。
代償:分断時や一部レプリカが到達不能なとき、システムは読み/書きを遅延または拒否して矛盾を避けるかもしれません。ユーザーはタイムアウトや「再試行してください」、一時的な読み取り専用といった挙動を目にします。
最終的一貫性(ユーザーが体験すること)
最終的一貫性は、更新が止まればすべてのレプリカは収束すると約束します。しかし今この瞬間に二人が見た結果が同じであることは保証しません。
ユーザーが気づくこと:最近更新したプロフィール写真が「戻る」、カウンタが遅れる、別デバイスにメッセージがすぐ見えないなど。
実用的な中間保証
フルの強い一貫性を要求せずに良い体験を得られる保証もあります:
- read-your-writes(自分の書き込みは自分が読める)
- monotonic reads(あるバージョンを見たら後で前には戻らない)
- 因果的一貫性(BがAに依存するなら、全員がAのあとにBを見る)
これらは「自分の変更が消えたように見えるな」という体験を避けるのに向いており、分断時にも比較的維持しやすいことが多いです。
期待に基づいて一貫性レベルを選ぶ
まずユーザーへの約束から始めてください:
- 不正確な読み取りが取り返しのつかない被害を生むなら(資金移動、在庫予約、権限変更など)、強い一貫性を優先し、一時的な可用性低下を受け入れる。
- しばらくの不一致を許容できる機能(いいね、閲覧数、フィードランキング)なら最終的/因果的一貫性で十分。
- 個人的な混乱(「保存したはずなのに見えない」)が主な痛みなら、read-your-writesやmonotonic readsを優先する。
一貫性はプロダクトの選択です:「間違っている」の定義を書き出し、その誤りを防ぐために必要な最も弱い保証を選びます。
可用性は単なる稼働率ではない
CAPでの可用性は単なる「稼働率自慢(ファイブナインズ)」ではなく、通信不確実性のときにユーザーに何を約束するかです。
速い成功 vs 正確な成功
レプリカが合意できないとき、多くの場合次の選択になります:
- 速い成功: 何かを素早く返す(古くてもよい)
- 正確な成功: 答えが現在のものであることを証明できるまで返さない
ユーザーは「アプリが動く」と「アプリが正しい」のどちらを感じるかで違います。フィードの少し古い表示は煩わしいが許容できる。口座残高が古いのは致命的です。
閉じて失敗する(fail closed) vs 開いて失敗する(fail open)
不確実性の際に見られる二つの振る舞い:
- fail closed: リクエストを拒否する(エラー、タイムアウト、読み取り専用)。正確さを守るがユーザーはブロックされる。
- fail open: ベストエフォートで応答する(キャッシュ、ローカルレプリカ、キューイング)。流れを保つが不一致を見せるリスクがある。
これは純粋に技術的な判断ではなくポリシーです。どこまでを推測してよいか、何を絶対に推測してはならないかをプロダクトが定義する必要があります。
部分的可用性も可用性である
可用性はめったに白黒ではありません。分断中、あるリージョンやユーザー群は成功し、他は失敗するという部分的可用性が起きます。これは局所的にレプリカが健康なら意図した設計にもできるし、ルーティング不均衡やクォーラム到達性のばらつきで偶発的にも起きます。
劣化モード:コアを残してリスクを制限する
実用的な中間解は劣化モードです:安全な操作は継続し、リスクの高い操作は制限します。例:閲覧や検索は許可するが、「資金移動」「パスワード変更」は一時停止する、など。
具体例:ユースケースに合わせたCAPの選択
CAPは抽象に見えますが、ネットワーク分断時にユーザーが何を体験するかに対応付けると現実的になります:システムは応答を続けるべきか、矛盾を避けるために停止すべきか。
在庫と注文:過剰販売のリスク vs チェックアウト停止
二つのデータセンターが注文を受け付けられないほど通信できないとします。
- チェックアウトを可用性優先で維持すると、各側が「最後の一つ」を売って過剰販売になる可能性があります。低額商品の場合は後でバックオーダーや謝罪で済ませられるかもしれませんが、限定販売では痛手です。
- 一貫性優先にすると、在庫をグローバルに確認できない間は新規注文をブロックするかもしれません。ユーザーは「後で試してください」と見るが、過剰販売は防げます。
支払いと残高:正確さ優先のパターン(理由)
お金は典型的に誤りが高コストなドメインです。分断中に二つのレプリカが独立して引き出しを受け入れると、口座が過剰引き落としされる可能性があります。
システムはクリティカルな書き込みに対して一貫性を優先する傾向があります:最新残高の確認ができない場合は処理を遅らせるか拒否する。可用性を一部犠牲にしても正確さ、監査性、信頼性を守ります。
チャット、フィード、分析:少し古くても可用性優先で良い場合
チャットやソーシャルフィードでは、数秒の遅延やいいね数のずれは通常許容されます。ここでは可用性を設計上優先するのが適切で、どの要素が「最終的に正しくなる」かを明確にしておけばよいでしょう。
要点:あなたのトレードオフはビジネス上の決定
CAPの「正解」は、間違うコスト(返金、法的リスク、ユーザー信頼の毀損、運用の混乱)によって決まります。どこで一時的な陳腐さを許容できるか、どこで閉じて保護するかを決めてください。
トレードオフを実現する設計パターン
分断時に何をするかを決めたら、その決定を現実にする仕組みが必要です。これらのパターンはデータベース、メッセージシステム、APIに広く現れます。
クォーラム:過半数の合意
クォーラムは単に「レプリカの過半数が合意する」ことです。たとえば5つのコピーがあれば過半数は3です。
読み/書きに過半数を要求すると、古いデータを返す可能性や競合が減ります。例えば書き込みが3つのレプリカの確認を必要とすると、孤立した二つのグループが異なる「真実」を受け入れる可能性が下がります。
トレードオフは遅延と到達性です:過半数に到達できなければ操作を拒否し、可用性より一貫性を選ぶことになります。
タイムアウト、リトライ、バックオフが体感的可用性を決める
多くの「可用性」問題はハードな故障ではなく遅いレスポンスです。短いタイムアウトは応答性を良く感じさせますが、遅い成功を失敗として扱う確率も上げます。
リトライは一時的な障害から回復できますが、過度のリトライは既に苦しむサービスにさらに負荷をかけます。バックオフ(再試行間隔を徐々に延ばす)とジッター(ランダム性)はリトライのスパイク化を防ぎます。
「常に応答する」という約束は多くのリトライとフォールバックを意味し、「決して嘘をつかない」は厳格な制限と明確なエラーを意味します。
乖離を許す場合のコンフリクト処理
分断中に可用性を維持するなら、レプリカが異なる更新を受け入れ後で和解する必要があります。一般的なアプローチ:
- 最終書き込み勝ち(LWW): タイムスタンプが最新のものを採る。簡単だがクロックがずれると有効な変更を捨てることがある。
- バージョンベクタ(上位概念): 更新が並行か上書きかを検出するための小さな“履歴”を付与する。
- マージルール: 変更をどう結合するかを定義する(例:カートは集合で合成、カウンタは加算、プロファイルは非空フィールドを優先)。データモデル段階で設計するのが最も効果的。
冪等性(idempotency):リトライを安全にする
リトライは重複を生む可能性があります:二重課金や同一注文の二重送信など。冪等性はそれを防ぎます。
一般的なパターンは**冪等キー(リクエストID)**を用いることです。サーバは最初の結果を保持し、同じキーのリクエストには同じ結果を返す——リトライで可用性を改善しつつデータ破壊を防げます。
実務的にCAPの前提を点検するチェックリスト
システム決定を行うとき、CAPは「分断が起きたら何が壊れるか?」を素早く監査するのに最も有用です。データベース機能、キャッシュ戦略、レプリケーションモードを選ぶ前にこのチェックリストを使ってください。
1) 短いCAPチェックリスト
順に問う:
- 何を正確にする必要があるか?(例:「銀行残高は絶対に負になってはならない」「在庫は過剰販売してはならない」「権限は正確でなければならない」)
- 何を稼働させ続けたいか?(例:チェックアウトエンドポイント、ログイン、カタログの読み取り)
- 何が一時的に劣化してよいか?(例:分析、レコメンデーション、プロフィール画像、最終アクセス表示)
分断が来たら、これらのうちどれを優先して守るかを決めることになります。
2) データ型とエンドポイントごとに決める
「うちはAPだ」という単一の全体設定は避けてください。代わりに以下で決める:
- データ種別: お金 vs いいね vs ログ
- エンドポイント:
place ordervsview ordervstrack shipment
例:分断中、paymentsへの書き込みはブロック(一貫性優先)し、product_catalogの読み取りはキャッシュで可用性を保つ、といった具合です。
3) 許容できる不整合を具体的に定義する
不整合を平叙で書き出してください:
- 時間的制限: 「カウントは5〜10分遅れてもよい」
- 許容幅: 「低需要品目の在庫は±1の誤差が許される」
- フィールド単位: 「配送ETAは古くてもよいが、注文合計は絶対に古くてはならない」
- ユーザー向け表現: 「決定的な状態の代わりに’保留中’を表示する」
不整合を例で説明できなければ、テストやインシデント時の説明が難しくなります。
4) まとめ+次に読むべきもの
- 分断は“ほしい保証”を強制的に二択にします。
- その選択をエンドポイントごとに明確にし、許容できる不整合を文書化してください。
次に読むと良いトピック:合意(/blog/consensus-vs-cap)、整合性モデルの解説(/blog/consistency-models-explained)、およびSLOとエラーバジェット(/blog/sre-slos-error-budgets)。
よくある質問
CAPはエンジニアにどんな問題を考えさせるか?
CAPは通信障害下のレプリケートされたシステムを考えるためのメンタルモデルです。ネットワークが遅い・パケットを落とす・分断されるときが最も有用で、レプリカ同士が確実に合意できない状況では次の二択を突き付けられます:
- 一貫性(Consistency): すべての人が同じ最新の値を見る
- 可用性(Availability): システムは成功応答を返し続ける
「分散は難しい」を製品と工学上の具体的な意思決定に変えるのがCAPの役割です。
いつ実際にCAPの状況に直面しているのか?
本当のCAP状況には両方が必要です:
- レプリケーション(同じデータを複数ノードが提供・受け付ける)
- 通信障害の現実的な可能性(分断、タイムアウト、長い遅延)
単一ノードや状態をレプリケートしていないシステムでは、CAPのトレードオフは核心的な問題にはなりません。
現実のシステムでネットワーク分断とは何を指すのか?
分断とは、マシンが動いていてもシステムの一部同士が要求される時間内に信頼してやり取りできないあらゆる状況です。
実際には分断は次のような形で現れます:
- タイムアウトを引き起こすレイテンシスパイク
- パケットのドロップやブラックホール
- ファイアウォールやルーティングの誤設定
- 応答できなくなるほど過負荷になったノード
アプリケーション観点では「遅い」は「ダウン」と同様に扱わなければならないことが多いです。
ユーザー視点では一貫性と可用性の違いは何か?
**一貫性(C)**はどこから読んでも最新の書き込みが反映されることを意味します。ユーザーは「自分が変更したら、みんな同じ最新値を見る」と感じます。
**可用性(A)**は、すべてのリクエストが成功応答(必ずしも最新ではない)を受け取ることを意味します。ユーザーは「アプリは動き続けるが、結果は古いかもしれない」と感じます。
分断が起きたとき、すべての操作に対して両方を同時に保証することは通常できません。
一貫性と可用性を選んで分断を無視できないのはなぜ?
分散システムでレプリケートしている限り、分断は無視できるものではありません。ネットワークを無効化することはできないので、分断が発生したときにシステムがどう振る舞うかを定義しておく必要があります。
「分断を許容する」とは、通信が壊れたときに、操作を拒否・一時停止して一貫性を守るか、最善応答を返して可用性を保つかを事前に決めておくことです。
分断時に一貫性優先(CP)はどんな振る舞いになるか?
一貫性を優先する場合、通常は:
- 合意が取れないと操作を拒否または遅延する
- 読み書きにクォーラムや過半数を要求する
- タイムアウトや「再試行してください」「読み取り専用」などのエラーをユーザーに見せる
これは、金銭移動、在庫確保、権限変更のように「間違うと取り返しがつかない」領域で一般的です。
分断時に可用性優先(AP)はどんな振る舞いになるか?
可用性を優先する場合、通常は:
- 分断の片側でも読み書きを受け付け続ける
- レプリカ間で一時的に乖離を許す
- 後で和解(マージルール、コンフリクト解決、手動レビュー)を行う
ユーザーはハードエラーが少ない代わりに、古いデータや重複した効果、後処理が必要な矛盾を目にすることがあります。
操作ごとに一貫性と可用性を混在させることはできるか?
はい。多くの実システムは操作やデータ型ごとに異なる戦略を採ります。よくある混合戦略:
- 読み取りは利用可能に、書き込みは厳格に(閲覧は可能だが、更新は失敗することがある)
- 重要アクションはクローズ(失敗して保護):支払いや在庫は閉じ、フィードや分析は開いたままにする
- 劣化モード:安全な操作だけを継続し、リスクの高い操作を一時的に無効化する
単一の「うちはAP/CP」ラベルに頼るのではなく、エンドポイントやデータ種別ごとに決めるのが実用的です。
「強い」と「最終的」以外に選べる一貫性保証は?
「完全に強い」や「完全に最終的」といった二極だけでなく、現実にはいくつかの有用な保証があります:
- 強い一貫性(線形化可能): 書き込みが反映された後は、後続のすべての読み取りがその書き込みを返す。分断時にはブロックや失敗が増える。
- 最終的一貫性: 更新が止まれば最終的にすべてのレプリカが収束するが、即時の一貫性は保証しない。
- 中間的な保証:
- 読み取り直後の自分の書き込みが見える(read-your-writes)
- 一度見たバージョンの前に戻らない(monotonic reads)
- 因果関係のあるイベントは順序が保たれる(causal consistency)
ユーザーにとって許容できない「誤り」を防げる最も弱い保証を選ぶのが実務的です。
CAPの前提をどう実地で検証・監視するか?
不整合が見える状況を意図的に作って、システムが設計通り動くか検証することが重要です。
- ステージング(慎重に本番)で分断をシミュレートする:トラフィックのブラックホール、ポート遮断、極端な遅延やパケットロスなど
- 検証項目:書き込みは拒否されるか受け付けられるか?読み取りは古いデータを返すか?再マージは自動か?復旧にどれくらいかかるか?
- 監視:稼働監視だけでなく、操作別エラー率、陳腐な読み取り(read-your-writes違反)やレプリカの乖離、タイムアウト・リトライの増加を追う
また、運用手順(runbooks)とユーザー向けメッセージを事前に用意しておくと、分断時の対応がスムーズになります。