クォーラムと読み書き整合性(R+W>N)
結果整合性のデータストアでも、R+W>N という一本の不等式を満たすだけで「最新値が読める」保証を取り戻せます。N・R・W を回すだけで整合性と可用性を自在に調整する原理をつかめます。
- 1.Dynamo 系は各キーを N 台に複製し、書き込みは W 台、読み取りは R 台の応答を待つ。R+W>N を満たすと読み集合と書き込み集合が必ず1台以上重なり、最新値を観測できる。
- 2.N・R・W は固定ではなくクエリごとに選べる調整つまみ。W を上げると整合性、下げると書き込み可用性が上がる。R も同様で、合計が N を超えるかで強整合か結果整合かが決まる。
- 3.複製のズレはバージョン(ベクタークロックなど)で検出し、読み取り時の読み修復とバックグラウンドの反エントロピーで収束させる。一時障害はヒンテッドハンドオフで吸収する。
クォーラムとは何を保証する仕組みか
Dynamo 系の分散データストア(Amazon Dynamo, Apache Cassandra, Riak, ScyllaDB など)は、各キーを N 台 のノードに複製します。この複製集合を preference list と呼び、コンシステントハッシュ法でキーの担当ノードから時計回りに N 台を選ぶのが定石です。問題は「N 台すべての応答を待つと1台でも落ちれば操作が失敗する」点で、これでは可用性を稼ぐための複製が逆に可用性を下げてしまいます。
そこで導入されるのが クォーラム(quorum、定足数) です。すべてを待つ代わりに、書き込みは W 台、読み取りは R 台 の応答が揃った時点で成功とみなします。N より少ない台数で確定できるため、一部のノードが落ちても操作を続行できます。鍵になるのが次の不等式です。
R + W > N … 読み集合と書き込み集合が必ず重なる(強整合の十分条件)
W > N/2 … 書き込み同士が必ず重なる(書き込みの直列化に必要)
なぜ R+W>N で最新値が読めるのか
原理は鳩の巣原理そのものです。ある書き込みは N 台のうち W 台に記録されます。続く読み取りは N 台のうち R 台に問い合わせます。R + W > N であれば、読み取りが触れる R 台と、最新の書き込みが触れた W 台は、台数の合計が N を超えるため 必ず1台以上で重複 します。その重複したノードは最新値を持っているので、読み取りは最新の書き込みを少なくとも1つは観測できます。
読み集合と書き込み集合が重なっても、R 台から返る値は新旧が混在し得ます(古い複製がまだ更新を受け取っていない)。そこで各値にはバージョン(後述のベクタークロックや単調増加のタイムスタンプ)が付与され、読み取り側は最も新しいバージョンを採用します。R+W>N は「最新値が応答集合の中に確実に含まれる」ことを保証し、バージョン比較が「その中からどれが最新かを選ぶ」役割を担います。両方が揃って初めて強整合な読み取りが成立します。
具体例を見ます。N=3 のとき、W=2, R=2 なら 2+2=4 > 3 で重なりが保証されます。書き込みは2台で確定できるので1台落ちても書け、読み取りも2台でよいので1台落ちても読めます。整合性と可用性のバランスが良く、これが Dynamo 系の最も一般的な既定値です。
N・R・W は可用性と整合性の調整つまみ
R と W は固定値ではなく、クエリごとに指定できる調整パラメータです。同じデータストアでも、操作の性質に応じて整合性レベルを変えられます。
| 設定 | R+W と N の関係 | 性質 | 向く用途 |
|---|---|---|---|
| W=N, R=1 | R+W>N を満たす | 書き込みは全台一致を待つ=遅く可用性低、読みは1台で速い | 読み多寄り・更新が稀 |
| W=1, R=N | R+W>N を満たす | 書き込みは1台で即時、読みが全台を確認=遅い | 書き込みを止めたくない |
| W=2, R=2 (N=3) | 4>3 で満たす | 整合性と可用性のバランス型 | 汎用の既定値 |
| W=1, R=1 (N=3) | 2>3 を満たさない | 最速・最も可用だが結果整合(古い値を読み得る) | ログ・カウンタなど緩い整合 |
ここから読み取れる原理は次の通りです。W を大きくするほど書き込みは「多くの複製に行き渡ってから成功」となり整合性は上がるが、待つ台数が増えるため書き込みの可用性とレイテンシは悪化します。R を大きくするほど読み取りは新しい値を取りこぼしにくくなるが、同様に読み取り可用性が下がります。そして R+W>N を割ると(例 W=1, R=1)、読み集合と書き込み集合が重ならないケースが生じ、古い値を読む可能性が出てきます。これが結果整合性の領域です。
R+W>N は理論上の十分条件ですが、実装によっては破れます。Dynamo 系は可用性のため、本来の N 台が落ちていると preference list の外の代替ノードへ書く sloppy quorum(緩いクォーラム) を使います。この場合「W 台に書けた」ものの、それが本来の担当 N 台と重ならず、後続の読み取りと交わらないことがあります。厳密な linearizability が必要なら、クォーラムだけでなくPaxos / Raftのような合意アルゴリズムが要ります。クォーラムが直接保証するのは『調整可能な整合性』であって、無条件の強整合ではありません。
バージョン管理:ベクタークロックと衝突
複製がズレた状態で、どの値が新しいかをどう判定するのでしょうか。単純な物理時刻(ウォールクロック)は、ノード間の時計ずれで前後が逆転し得るため信頼できません。Dynamo はこれに ベクタークロック(version vector) を用います。
ベクタークロックは [(ノードID, カウンタ), ...] の組で、各ノードが自分の更新ごとにカウンタを増やします。2つのバージョン A と B を比べ、A のすべての要素が B 以上(かつ少なくとも1つは真に大きい)なら「A は B の子孫(A が新しい)」と判定でき、因果関係を保ったまま新旧を順序付けられます。
書き込み1(ノードSx): D1 [(Sx,1)]
書き込み2(ノードSx): D2 [(Sx,2)] ← D1 を上書き(祖先関係)
分断中に別経路で更新: D3 [(Sx,2),(Sy,1)] ← D2 から分岐
D4 [(Sx,2),(Sz,1)] ← D2 から分岐
D3 と D4 は互いに祖先でない = 衝突(並行更新)
どちらも相手の祖先でない場合、それは並行して起きた衝突です。Dynamo はこれを自動で潰さず、両方の値(兄弟、siblings)を保持して読み取り時にアプリへ返し、アプリ側のマージ(例:買い物カゴなら和集合)に委ねます。一方 Cassandra は実装を簡素化するため last-write-wins(タイムスタンプが新しい方を採用)を採り、衝突を自動解決する代わりに更新を失う可能性を受け入れています。設計思想の違いです。
読み修復とヒンテッドハンドオフ:ズレを収束させる
クォーラムは「読めた瞬間に最新を含む」ことは保証しますが、遅れている複製を放置すれば差は広がる一方です。Dynamo 系はズレを能動的に埋める2つの仕組みを持ちます。
読み修復(read repair) は、読み取りのついでに修復する仕組みです。R 台から値を集めた際にバージョンの食い違いを検出したら、最新値を遅れていたノードへ非同期に書き戻します。読まれるキーほど自然に修復されるため、ホットなデータは速く収束します。逆に読まれないキーは修復が走らないため、これを補うのが定期的に全複製を突き合わせる**反エントロピー(anti-entropy)**で、差分検出には Merkle ツリー(ハッシュ木)が使われます。
ヒンテッドハンドオフ(hinted handoff) は、一時的なノード障害を吸収する仕組みです。書き込み時に本来の担当ノードが落ちていると、別の生存ノードがその書き込みを「これは本来 Sx 宛て」というヒント付きで肩代わりして預かります。Sx が復帰すると、預かっていたノードがヒントをたどって書き込みを転送し、預かりぶんを削除します。これにより、一時障害中も書き込み可用性を保ったまま、復帰後に整合性を回復できます。
読み修復は「読まれたキーの遅延複製」を、反エントロピーは「読まれないキーの取り残し」を、ヒンテッドハンドオフは「書き込み時の一時的なノード不在」をそれぞれ担当します。守備範囲が違うため、3つは競合せず相互補完します。どれか1つでは結果整合性の収束を保証できない、と整理すると理解しやすいです。
ヒントを預かったノードがヒント転送前に落ちると、その書き込みは失われ得ます。また sloppy quorum とヒンテッドハンドオフの組み合わせは「W 台に書けた」という成功応答を返しつつ、実際には正規の複製に届いていない状態を生みます。クラスタ全体が高負荷だとヒントが溜まり、復帰時の転送が新たな負荷スパイクを招くこともあります。可用性のための仕組みが、条件次第で整合性と安定性のリスクに転じる点は要注意です。
まとめ
クォーラムは、各キーを N 台に複製したうえで書き込みを W 台・読み取りを R 台で確定し、R+W>N を満たせば読み集合と書き込み集合が必ず重なって最新値を観測できる、という鳩の巣原理に基づく仕組みです。N・R・W はクエリごとに回せる調整つまみで、合計が N を超えるかどうかで強整合と結果整合を、W と R の大小で整合性と可用性のトレードオフを連続的に制御できます。複製のズレはベクタークロックで因果順序付けし、読み修復・反エントロピー・ヒンテッドハンドオフで能動的に収束させます。ただし sloppy quorum 下では強整合が破れ得るため、厳密さが要るならPaxos / Raftを、複製戦略全体はレプリケーションとシャーディングやCAP 定理と併せて設計判断するのが定石です。
データベース Article
クォーラムと読み書き整合性(R+W>N)を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
分散システム
比較で見る軸
難易度: advanced / カテゴリ: データベース / タグ数: 5
導入後に効く点
N・R・W は固定ではなくクエリごとに選べる調整つまみ。W を上げると整合性、下げると書き込み可用性が上がる。R も同様で、合計が N を超えるかで強整合か結果整合かが決まる。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- データベース
- タグ数
- 5
判断チェックリスト
- 自社の用途が「分散システム / 結果整合性」に近いか確認する。
- 強みである「Dynamo 系は各キーを N 台に複製し、書き込みは W 台、読み取りは R 台の応答を待つ。R+W>N を満たすと読み集合と書き込み集合が必ず1台以上重なり、最新値を観測できる。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。