CAP の availability 模擬

生田 陸人
LuaGate エンジニア / 現役エンジニア
編集 LuaGate編集部

CAP の availability 模擬

このレッスンで分かること

  • 複数のサーバー(ノード)にまたがって動く分散データベースを設計するとき、必ずぶつかる壁があります
  • CAP 定理が言っているのは、「3 つすべてを完全には満たせない
  • 図のポイント (テキスト併記)

CAP の availability 模擬 とは

CAP 定理の Availability(可用性)を、複数ノード上の最新値を多数決で返す関数として実装します。

複数のサーバー(ノード)にまたがって動く分散データベースを設計するとき、必ずぶつかる壁があります。それが CAP 定理 です。CAP は次の 3 つの英単語の頭文字を取っています。

  • C = Consistency(強整合性)どのノードに読みに行っても、必ず最新の値が返る
  • A = Availability(可用性)一部のノードが落ちても、システムは応答を返し続ける
  • P = Partition tolerance(分断耐性)ネットワークが分断されても動き続ける

CAP 定理が言っているのは、「3 つすべてを完全には満たせない。ネットワーク分断(P)が起きたとき、C と A のどちらかを諦めるしかない」 ということです。

diagram (will load when visible)

図のポイント (テキスト併記)

  • 一般的な銀行系の DB は CP 寄り、Cassandra や DynamoDB などのクラウドストレージは AP 寄りで設計されている

一般的な銀行系の DB は CP 寄り、Cassandra や DynamoDB などのクラウドストレージは AP 寄りで設計されている。

Availability を模した「多数決リード」

今回の課題では、複数ノードに保存された値から 「過半数(quorum)のノードが同意した値」を返す 処理を実装します。これは AP システムでよく使われる quorum read の単純化版です。

例えば 5 ノードある DB が次のように値を保持しているとします。

nodevalue
n1"v2"
n2"v2"
n3"v1"
n4"v2"
n5""(ダウン中)

5 ノード中、v2 が 3 票、v1 が 1 票、空文字(ダウン中)が 1 票。過半数(3 票以上)を取った v2 が「合意された値」として返ります。1 ノードが落ちていても答えを返せるので Availability が確保されている わけです。

Python

def quorumRead(replicas): counts = {} for v in replicas: if not v: continue counts[v] = counts.get(v, 0) + 1 total = len(replicas) quorum = total // 2 + 1 # 過半数 for v, c in counts.items(): if c >= quorum: return v return "" # 合意なしは空文字を返す

過半数(majority)は len // 2 + 1。5 なら 3、3 なら 2、4 なら 3。

コードでの考え方

入力は replicas: list[str]。空文字 ""「ダウン中ノード」 とみなして集計から外します。出力は 過半数を取った値、または合意できなければ空文字 ""

JavaScript

function quorumRead(replicas) { const counts = {}; for (const v of replicas) { if (!v) continue; counts[v] = (counts[v] || 0) + 1; } const quorum = Math.floor(replicas.length / 2) + 1; for (const [v, c] of Object.entries(counts)) { if (c >= quorum) return v; } return ""; }

ダウン中ノードを表すのに null を使いたいところだが、今回は言語横断で動かしやすい空文字 "" で代用する。

よくある間違い

過半数の計算を len / 2 (ちょうど半分)にすると、5 ノード中 2 票でも合意とみなしてしまう バグが起きます。半分より多い を意味する len // 2 + 1 を使いましょう。

また、最初に過半数を超えた値で return しない と、複数の値が両方とも閾値を超えたとき(実際は起きないが)の振る舞いが曖昧になります。1 つ見つけたら即 return が安全です。

CAP の現実 — eventual consistency

AP システムは、Network partition の最中は一時的に値が割れることを許容します。やがてノード間でレプリケーションが終わると全ノードが同じ値に揃う、これを eventual consistency(結果整合性) と呼びます。SNS の「いいね数が一瞬古く見える」「分散キャッシュが少し遅れて反映される」のはこの仕組みです。

「即時に正確」を取るか「常に応答が返る」を取るか — 設計者の宿題は永遠に終わらない。

やってみよう

replicas 配列を入力に、過半数を取った値(または空文字 "")を返す quorumRead を実装してください。空文字は集計から除外する、過半数は len // 2 + 1 という 2 点に注意。

よくある質問

Q. このトピックを覚える意味は何ですか?

A. 分散 DB や NoSQL を選定するとき、DynamoDB・Cassandra・MongoDB など各サービスが「CP 寄り」「AP 寄り」のどちらで設計されているかを判断する土台になります。マイクロサービス間でデータを共有する設計や、レプリケーションの遅延を許容するかどうかの議論でも、CAP 定理の理解は不可欠です。

Q. 実務でこの知識を使う場面は?

A. API の Content-Length 計算、ファイルアップロードのサイズ制限、画像処理での色深度計算など、低レベルな数値を扱う場面で頻出します。OS・ネットワーク・暗号の理解にも繋がるため、CS の共通言語と思って習得しておくと一生使える知識です。

Q. 他の章とどう繋がりますか?

A. 後続の章で扱うデータ構造(スタック・キュー)、アルゴリズム(探索・ソート)の基礎になります。CAP 定理で「整合性と可用性のトレードオフ」を掴んでおくと、後続の疎結合・密結合やトランザクション処理(ACID)でなぜ設計上の制約が生まれるのかが腹落ちしやすくなります。分散環境における整合性の難しさを先に体感することで、ACID がなぜ重要なのかも理解が深まります。

次のレッスン

次は URL ルーティング で、MVC アーキテクチャにおける URL と Controller の対応付け(ルーティング)の仕組みを実装しながら学びます。

事前確認 — 進む前に次の 3 つができることを確認しましょう。

  1. CAP 定理 の要点を自分の言葉で説明できる
  2. このレッスンの最小コード (または操作手順) を見ずに書ける
  3. 練習問題やクイズで間違えた箇所を読み直して理解した

理解度チェック (30 秒)

Q. CAP 定理 とは何か、1 文で説明してください。

この章のポイント

A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。

関連レッスン**

要件

  1. 空文字(dead node)は集計から除外する
  2. 過半数は len // 2 + 1 で計算する
  3. 過半数を取った値があれば返し、なければ空文字を返す

入出力例

test-cases.txt

quorumRead(["v2","v2","v1","v2",""])"v2" quorumRead(["v1","v2","v3"])"" quorumRead(["v1","",""])"" quorumRead(["v1","v1","v1"])"v1" quorumRead(["a","a","b","b"])"" quorumRead(["x","x","x","",""])"x"

ヒント

main.py
main.py
学習モード

メモ

CAP の availability 模擬

⌘S で保存