CAP定理とは - 分散システムで一貫性と可用性のどちらを守るか(PACELCまで整理)

CAP定理とは - 分散システムで一貫性と可用性のどちらを守るか(PACELCまで整理)

作成日:
読了:18
更新日:
この記事を読む人におすすめPR / Amazonアソシエイト

当サイトは Amazon.co.jp を宣伝しリンクすることで紹介料を得る手段を提供する、Amazonアソシエイト・プログラムの参加者です。価格・在庫はリンク先の最新情報をご確認ください。

分散データベースやマイクロサービスを設計していると、必ず「一貫性を取るか、可用性を取るか」という問いに突き当たります。この選択を理論として整理したのがCAP定理です。ところが、この定理は「3つのうち2つを選べ」という有名なフレーズとともに、しばしば誤解されたまま語られてきました。この記事では、CAP定理の正確な定義から出発し、有名な誤解の正体、分断が起きたときに実際に何が起きるのか、そして通常時のトレードオフを補うPACELC定理までを、原典を一次ソースに順序立てて整理します。

分散システムでデータをどう分割するかという観点はコンシステントハッシュ法で扱いました。この記事は、そうして複数ノードに分散させたデータを「どこまで一致させ続けるか」という、一段上のトレードオフの話になります。

CAP定理とは何か

CAP定理は、Eric Brewerが2000年のPODC(分散コンピューティング原理シンポジウム)の基調講演で提示した主張です。着想自体は1999年にさかのぼります。当初は「予想(conjecture)」でしたが、2002年にMITのSeth GilbertとNancy Lynchが非同期ネットワークモデルで形式的に証明し、「定理(theorem)」と呼ばれるようになりました。

主張の核心は次のとおりです。ネットワークで結ばれた共有データシステムは、一貫性・可用性・分断耐性の3つを同時に完全には満たせない。3つの頭文字を取ってCAPと呼びます。

  • Consistency(一貫性): すべてのクライアントが、どのノードにアクセスしても同じ最新のデータを見られること。Gilbertらの証明では、これを線形化可能性(linearizability)、別名アトミック一貫性として厳密に定義しています。ある書き込みが完了した後の読み取りは、必ずその書き込み以降の値を返すという強い保証です。
  • Availability(可用性): 障害のない全ノードが、受け取ったすべてのリクエストに(最新である保証はなくても)必ず応答を返すこと。「エラーやタイムアウトで黙り込まない」という性質です。
  • Partition tolerance(分断耐性): ノード間で任意の数のメッセージが失われたり遅延したりしても、システムが動作を続けられること。ネットワークが分断されても止まらない、という性質です。

ここで最初の注意点です。CAPのCは、後述するように「線形化可能性」という単一コピー一貫性だけを指します。データベースのACIDにおけるC(一貫性)とは意味が異なるので、まずこの違いから押さえます。

CAPのCはACIDのCとは別物

CAPを学ぶうえで最もつまずきやすいのが、この「2つのC」の混同です。名前は同じ「Consistency」ですが、指すものがまったく違います。

トランザクションとACID・分離レベル入門で整理したとおり、ACIDのC(一貫性)は「トランザクションの前後で、データが制約や外部キーなどの整合性ルールを満たした正しい状態に保たれること」を指します。つまりデータの意味的な正しさ・不変条件の維持の話です。

一方でCAPのCは、Brewer本人が2012年の再考論文で明言しているとおり、単一コピー一貫性(線形化可能性)のみを指し、ACID一貫性の厳密な部分集合にすぎません。複数のレプリカがあっても、あたかも1つのコピーしか存在しないかのように、全クライアントが同じ最新値を見られるか、という話です。制約が守られているかどうかは問いません。

両者を対比すると、次のように整理できます。

観点ACIDのC(Consistency)CAPのC(Consistency)
指すもの制約・不変条件を満たす正しい状態線形化可能性(単一コピー一貫性)
主な文脈単一データベースのトランザクション複数ノードに複製されたデータ
誰が保証するかアプリとDBの制約定義レプリケーションと合意の仕組み
関係より広い概念ACIDのCの一部分(部分集合)

同じ単語でも文脈が違えば意味が変わる、という典型例です。「CassandraはCAPのCを緩めている」という話と「トランザクションのC(制約)を守る」という話は、まったく別のレイヤーだと理解しておくと混乱しません。

「3つから2つを選ぶ」という誤解

CAP定理は長らく「CAP のうち2つを選べ(pick two)」というフレーズで広まりました。CA・CP・APの3タイプから1つを選ぶ、という三択の図です。しかしBrewer自身が2012年の再考論文で、この言い方は誤解を招く(misleading)とはっきり述べています。

なぜ誤解なのか。理由は分断(P)は選択肢ではなく前提だからです。ネットワークはいつか必ず分断されます。ケーブルが抜ける、スイッチが落ちる、パケットが遅延する。これらを「起きないことにする」選択はできません。したがって、実ネットワークで動くシステムにとって分断耐性を捨てるCA型は、事実上あり得ない選択肢です。

Brewerの整理をまとめると、CAP定理が本当に語っているのは次のことです。

  • 分断が起きていない通常時は、一貫性も可用性も両方諦める理由はない。両立できる。
  • 分断が実際に起きたときだけ、一貫性(C)と可用性(A)のどちらを優先するかを選ぶ必要がある。

つまりCAP定理は「常に2つしか選べない」ではなく、「分断時に、CとAのどちらかを一時的に手放す」という、条件付き・局所的なトレードオフを述べたものだったのです。この判断の流れを図にすると次のようになります。

Loading diagram...

この図の右下、通常時の枝で登場するPACELCについては後半で扱います。まずは分断中の左側、CPとAPの分かれ道を具体的に見ていきます。

分断時にCとAのどちらを守るか

分断が起きた瞬間、システムは避けられない二択を迫られます。あるノードが、別のノードと通信できない状態で書き込み要求を受け取ったとしましょう。とれる行動は2つです。

操作を中止する(一貫性優先、CP)。他のノードと同期が取れないなら、古い値や矛盾した値を返すリスクを避けるため、その操作をエラーにするかブロックします。一貫性は守られますが、応答を返せないので可用性を犠牲にします。これがCP型の振る舞いです。

操作を続行する(可用性優先、AP)。同期が取れなくても、手元のノードだけで書き込みや読み取りに応答します。可用性は守られますが、分断の反対側と値が食い違うため、その瞬間の一貫性を犠牲にします。これがAP型の振る舞いです。

この対応関係は絶対に取り違えないでください。整理すると次のとおりです。

分断中の選択守るもの犠牲にするもの分類
操作を中止する一貫性(C)可用性(A)CP
操作を続行する可用性(A)一貫性(C)AP

具体例で考えます。2つのノードAとBがネットワーク分断で互いに通信できない状況で、クライアント1がノードAに、クライアント2がノードBに、それぞれ別の値を書き込もうとします。AP型とCP型で挙動がどう分かれるかを示したのが次のシーケンス図です。

Loading diagram...

AP型は両方の書き込みを受理し、分断が解消してから「どちらの値を最終値にするか」を後で調停します(ベクタークロックや最終書き込み優先などの手法があります)。CP型は、たとえば過半数(クォーラム)を取れない少数派側の書き込みを拒否し、そもそも矛盾を作らせません。ネットワーク分断がなぜ起きるのかという物理層・伝送層の背景は、TCPと3ウェイハンドシェイクのような通信の仕組みを押さえておくとイメージしやすくなります。

Brewerによる再考: 分断と遅延を結びつける

2012年、Brewerは「CAP Twelve Years Later」という再考論文(IEEE Computer誌)を発表しました。ここで重要な視点が加わります。分断とは、絶対的な断線だけを指すのではなく、通信の時間境界であるという捉え方です。

Brewerは「ある時間内に一貫性を達成できなければ、それは分断が起きたとみなせる」と述べています。つまり、ノード間の応答が一定時間内に返ってこなければ、システムはそれを分断として扱い、CとAのどちらを優先するかを決めなければなりません。物理的にケーブルが切れていなくても、単に遅延が大きいだけで「実質的な分断」が発生し得るわけです。

この視点は、CAP定理を「めったに起きない障害時の話」から「日常的な遅延の話」へと引き寄せます。ミリ秒単位でタイムアウトを設定すれば、わずかな遅延も分断として扱われ、頻繁にCとAの選択が発生します。逆にタイムアウトを長くすれば、応答を待つ間、可用性(応答性)が下がります。分断は避けられない前提であり、それも二値的なオンオフではなく、遅延という連続量として現れるのだ、というのが現代的な理解です。

そしてこの「通常時の遅延と一貫性の綱引き」を、CAP定理そのものは語っていません。それを補うのが次のPACELCです。

PACELC定理: 通常時のレイテンシと一貫性

PACELC定理は、Daniel Abadiが2010年のブログ記事で提示し、2012年のIEEE Computer誌の論文で定式化したものです。CAP定理が「分断時」しか語らないことへの不満から生まれた、拡張版と言えます。

名前の読み解き方はこうです。

  • PAC: Partition(分断)が起きたら、Availability と Consistency のトレードオフ。これはCAP定理と同じ内容です。
  • ELC: Else(それ以外、つまり通常時)は、Latency(レイテンシ)と Consistency(一貫性)のトレードオフ。

つまりPACELCは、「分断が起きればAとCの綱引き、分断が起きていない通常時でもレイテンシとCの綱引きがある」と、2つの局面をひとつの枠組みでとらえます。

なぜ通常時にもレイテンシと一貫性の綱引きが生じるのでしょうか。強い一貫性を保つには、書き込みを複数のレプリカに同期させ、過半数の確認を待ってから応答する必要があります。この「待ち」が遅延を生みます。逆に、1つのノードで即座に応答して他レプリカへ非同期に伝播すれば速いですが、その瞬間はレプリカ間で値が食い違い、一貫性が緩みます。分断がなくても、レプリケーションがある限りこのトレードオフは消えません。

PACELCの分類は「PAC側の選択/ELC側の選択」の組み合わせで表現します。一般的な説明例を挙げると次のとおりです(あくまで一般的な整理であり、設定で変わります)。

システム(一般的な説明)分断時(PAC)通常時(ELC)表記
強一貫なRDB・合意ベースのストア一貫性優先(PC)一貫性優先(EL の反対、C)PC/EC
可用性重視のキーバリューストア可用性優先(PA)低遅延優先(EL)PA/EL

CAPだけを見ていると「うちは分断なんてめったに起きないから関係ない」と思いがちですが、PACELCの視点では通常運転しているまさに今も、レイテンシと一貫性のどちらを取るかを設計上選んでいることになります。ここがPACELCの実務的な価値です。

実システムはどう分類されるか(留保付き)

実在のデータベースをCP型・AP型に分類した図はよく見かけますが、注意が必要です。公式ドキュメントが自ら「わが社はCP型です」と名乗る例はむしろ少なく、多くは設定によって挙動が変わります。以下は「一般にこう説明される」という留保付きの整理として読んでください。

CP寄りと説明されるもの
  • etcd: Raft合意アルゴリズムを用いる分散キーバリューストアです。公式ドキュメントが読み取りについて線形化可能性(linearizability)を明記している、数少ない例です(既定の読み取りは線形化可能で、性能重視の直列化可能読み取りも選べます)。ZooKeeperも同様に合意ベースで、一貫性を重視する系として語られます。
  • MongoDB: 既定では一貫性寄りとされますが、read concern・write concern の設定によって保証の強さを調整できます。単純に固定の型として断じるより、設定次第と考えるのが正確です。
  • HBase: 強い一貫性を重視する設計として説明されることが多いストアです。
AP寄りと説明されるもの
  • Cassandra: 可用性重視で語られますが、チューナブル・コンシステンシ(tunable consistency)により、リクエスト単位でconsistency level(ONE・QUORUM・ALLなど)を指定できます。QUORUMを使えば強めの一貫性側に寄せられるため、「常にAP」と断定するのは不正確です。
  • DynamoDB: Amazon Dynamo論文の系譜で可用性重視とされますが、強一貫読み取り(strongly consistent read)のオプションが用意されています。読み取りを強一貫にするかどうかを選べるため、単純なAP断定はできません。
  • Riak: Dynamoの設計思想を継ぐ分散データベースで、AP寄りの代表例として挙げられます。
CA型について

理論上は「分断耐性を捨てて一貫性と可用性を取る」CA型が図には描かれますが、実ネットワークで分断を完全に避けることはできないため、CAは現実的な選択肢ではありません。「分断は避けられない前提であり、問題は分断時にCとAのどちらを優先するかだ」というのが、Brewerの再考以降の共通理解です。

なお、ここで扱っているのは「複数ノード間で値をどこまで一致させるか」というシステム全体の一貫性の話であり、各ノードの内部でクエリをどう速くするかというデータベースインデックスの設計とは別のレイヤーです。両者を切り分けて考えると、性能と一貫性の議論が混ざらずに済みます。

NOTE

ここに挙げた分類は、製品・バージョン・設定によって変わります。設計判断の際は必ず、使用するバージョンの公式ドキュメントで read/write の一貫性保証を確認してください。「このDBはAP型だから」という一言で片付けず、どの設定でどの保証が得られるかを個別に確認するのが安全です。

結果整合性とBASE

AP寄りのシステムがよりどころにするのが結果整合性(eventual consistency)という考え方です。定義はシンプルで、そのデータへの新しい更新が止まれば、いずれ全レプリカが同じ値に収束するという保証です。「いつか一致する」を約束するだけで、「今この瞬間に一致している」は約束しません。

分断中に別々の値を受理しても、分断が解消して更新が落ち着けば、レプリカ同士が値をすり合わせて最終的に一致します。線形化可能性のような「常に最新」の強い保証と比べると弱いですが、その代わりに高い可用性と低いレイテンシが得られます。

この設計哲学を表す言葉がBASEです。ACIDの対極として提唱された頭字語で、次の3つから成ります。

  • Basically Available(基本的に可用): 一部に障害があっても、システム全体としては応答を返し続ける。
  • Soft state(柔らかい状態): 入力がなくても、レプリケーションの伝播などで状態が時間とともに変化し得る。
  • Eventual consistency(結果整合性): 更新が止まれば、いずれ一貫した状態に収束する。

ACIDが「厳密な一貫性を守るために、必要なら待たせる・止める」方向なのに対し、BASEは「まず応答すること・止まらないことを優先し、一貫性は後から追いつかせる」方向です。どちらが正しいという話ではなく、扱うデータの性質に応じて選ぶトレードオフです。たとえば銀行残高はACID寄りの強い一貫性が要りますが、SNSの「いいね」数のカウントは多少の遅れや一時的なズレが許容でき、BASE寄りで可用性を優先する判断が理にかないます。

まとめ

CAP定理は、分散システムの一貫性と可用性のトレードオフを最初に理論として示した、基礎中の基礎です。ただし有名な「3つから2つ」というフレーズは誤解を招くため、正確な理解が欠かせません。要点を振り返ります。

  • CAP定理は、共有データシステムが一貫性・可用性・分断耐性を同時に完全には満たせないという主張。Brewerが2000年に提示し、2002年にGilbertとLynchが証明した。
  • CAPのCは線形化可能性(単一コピー一貫性)であり、ACIDのC(制約の維持)とは別物。CAPのCはACIDのCの部分集合。
  • 「3つから2つ」は誤解。分断(P)は選択肢ではなく前提であり、CAPが本当に語るのは「分断が実際に起きたとき、CとAのどちらを優先するか」。
  • 分断時に操作を中止すれば一貫性優先のCP、操作を続行すれば可用性優先で一貫性を犠牲にするAP。この対応を取り違えない。
  • Brewerの2012年再考は、分断を「通信の時間境界」と捉え、遅延と分断を結びつけた。
  • PACELC定理は、分断時のA対Cに加え、通常時のレイテンシ対一貫性のトレードオフを補う。
  • 実システムの分類は設定で変わるため、etcd・Cassandra・MongoDB・DynamoDBなどは留保付きで理解し、公式ドキュメントで保証を確認する。
  • 結果整合性は「更新が止まればいずれ収束する」保証。BASEはACIDの対極で、可用性を優先する設計哲学。

「一貫性と可用性、どちらを取るべきか」という問いに単一の正解はありません。CAP定理とPACELCは、その問いをいつ・何と何のトレードオフとして考えればよいかを整理する道具です。扱うデータの性質に応じて、意識的に選び取るための土台として使ってください。

参考リンク

UUID と ULID 入門 - 分散システムで衝突しない ID を、時系列に強く設計する

UUID と ULID 入門 - 分散システムで衝突しない ID を、時系列に強く設計する

14

分散システムの一意な ID 設計を、UUID と ULID を軸に整理します。RFC 9562(2024 年発行)が標準化した UUIDv7、UUIDv4 のランダム性が DB インデックスに与える影響、ULID の 128 ビット構成と時系列ソート、生成コード例、そしてタイムスタンプ露出などのセキュリティ注意点まで、一次ソースを裏取りしてまとめます。

ブルームフィルタとは - 少ないメモリで「たぶん在る・確実に無い」を判定する確率的データ構造

ブルームフィルタとは - 少ないメモリで「たぶん在る・確実に無い」を判定する確率的データ構造

15

ブルームフィルタ(Bloom filter)を基礎から解説します。偽陽性はあるが偽陰性は無い性質、mビット配列とk個のハッシュ関数によるadd/query、偽陽性率と最適kの導出、O(k)の計算量、Cassandra/RocksDBなどの実運用、Counting/Scalable/Cuckooといった変種までを一次ソースで整理します。

コンシステントハッシュ法とは - 分散システムでノードを増減してもキャッシュが崩れない仕組み

コンシステントハッシュ法とは - 分散システムでノードを増減してもキャッシュが崩れない仕組み

14

コンシステントハッシュ法(Consistent Hashing)を基礎から解説します。単純な mod N ハッシュがノード数変更でほぼ全キー再配置になる問題、ハッシュリングと時計回り割り当て、仮想ノードによる負荷平準化、再配置がなぜ平均 K/N で済むのか、そして Jump Consistent Hash・Rendezvous(HRW)・Maglev といった発展、DynamoDB/Cassandra/memcached(ketama) での実運用まで、原論文を一次ソースに整理します。