Engineering
Glossvation Engineering
クラウド

Cassandra 一貫性レベルの選び方 — ONE から ALL まで、現場で何を使うか

Cassandra の Tunable Consistency を Read/Write 別に整理。QUORUM の数式、R+W>RF の原則、マルチ DC での LOCAL_QUORUM 推奨、トレードオフの実例つき。

Glossvation ·

Cassandra の 「調整可能一貫性」

Cassandra の一貫性 (Consistency Level, CL) は 固定ではなく、Read/Write ごとにクエリ単位で選択できる のが特徴です。

強整合が要るときは QUORUM、ベストエフォートでいいときは ONE …のように、 データごと・操作ごとに整合性と可用性のバランスを調整 できます。これが 「Tunable Consistency」 と呼ばれる理由。

前提として Cassandra データモデル入門 と Cassandra 読み書き内部フロー を把握している前提で進めます。

一貫性レベル一覧

CQL では以下のレベルが選べます (Write/Read とも同じ名前を使う):

Level確認するレプリカ数用途目安
ALL全レプリカ使わない (1 ノード落ちたら書けない)
EACH_QUORUM各 DC の過半数クロス DC で強整合が要る場合
QUORUM全 DC 通算の過半数単 DC + 強整合
LOCAL_QUORUM自 DC の過半数本番の標準 (マルチ DC)
ONE / TWO / THREE指定数のレプリカベストエフォートで速さ優先
LOCAL_ONE自 DC の 1 レプリカ分析用、キャッシュ的用途
ANY書き込み時のみ、Hint も可可用性最優先、整合性不問

QUORUM の数式

QUORUM = (RF の合計 / 2) + 1  (端数切り捨て)

例: RF = 3 なら QUORUM = 2 例: RF = 5 なら QUORUM = 3

EACH_QUORUM は DC ごとに QUORUM を要求 (DC1 で 2、DC2 で 2、など全 DC で過半数を満たす必要がある)。 LOCAL_QUORUM は自分の DC だけ QUORUM を満たせば良い。

強整合を得る黄金ルール: R + W > RF

分散システムで「書き込んだ直後に、必ず最新を読める」= 強整合を得たいなら、 Read CL + Write CL が RF (レプリカ数) より大きい を満たすようにします。

例: RF = 3

  • Write: QUORUM (2)、Read: QUORUM (2) → 2 + 2 > 3 ✓ 強整合
  • Write: ONE (1)、Read: ALL (3) → 1 + 3 > 3 ✓ 強整合 (ただし Read 高コスト)
  • Write: ONE (1)、Read: ONE (1) → 1 + 1 > 3 ✗ 結果整合 (古いデータを読む可能性)

本番の 定石は Write LOCAL_QUORUM + Read LOCAL_QUORUM: 同 DC 内で R + W > RF/DC を満たしつつ、クロス DC 遅延に引っ張られない。

書き込み CL の選び方

ケース推奨 CL
本番 (マルチ DC)LOCAL_QUORUM
単 DC で強整合QUORUM
ベストエフォート (ログ、イベント)ONE / LOCAL_ONE
書けさえすればよい (監査用など)ANY
全 DC で強整合 (金融系跨ぎ)EACH_QUORUM (遅い)

ALL を避ける理由

  • 1 ノードでも落ちていると書き込み不能 → 可用性が破綻
  • Rolling Restart 中に 100% 失敗
  • Cassandra の AP 哲学と真逆

ALL を選びたくなる場面はたいてい設計の見直しが必要なサイン。

読み取り CL の選び方

ケース推奨 CL
本番 (マルチ DC)LOCAL_QUORUM (Write も同じなら強整合)
分析バッチLOCAL_ONE (レイテンシ低、整合緩)
キャッシュ代わりONE
強整合絶対 (読み替え安全性)ALL (非推奨、高リスク)

マルチ DC での落とし穴

QUORUM は全 DC 通算の過半数なので、ネットワーク遅延で DC 間の RTT が加算されて遅くなります。 マルチ DC では基本 LOCAL_QUORUM にして、必要時のみ EACH_QUORUM を検討。

実務でよくある構成例

A. 通常の業務データ (3 DC, RF=3 each)

  • Write: LOCAL_QUORUM
  • Read: LOCAL_QUORUM
  • 強整合を同 DC 内で保証、クロス DC 遅延の影響を受けない

B. 時系列イベント / ログ (RF=3, 1 DC)

  • Write: ONE (速度優先)
  • Read: LOCAL_ONE (順序は多少ズレても良い)
  • 書き込みスループット最大化、整合性要件は緩い

C. 金融系台帳 (2 DC, RF=3 each)

  • Write: EACH_QUORUM (両 DC で強整合保証)
  • Read: LOCAL_QUORUM
  • クロス DC でも書き込みの整合を担保 (レイテンシ犠牲)

D. LightWeight Transaction (LWT)

強整合だけでなく 線形化可能性 (compare-and-set) が必要なら SERIAL / LOCAL_SERIAL を使います:

INSERT INTO users (id, email) VALUES ('u1', 'a@example.com') IF NOT EXISTS;

ただし LWT は Paxos を内部で走らせるため 通常 Write の 4〜5 倍遅い 。 「頻繁に使うな、必要な箇所だけ」 が鉄則。

落とし穴

1. 単体テストが本番より厳しい CL になっている

ローカル開発では RF=1 なので CL は何を指定してもほぼ同じ。 本番で LOCAL_QUORUM を指定したら急に遅くなった、というケースがあります。 本番と同じ RF で負荷テスト をしましょう。

2. ドライバのデフォルト CL を信じすぎる

DataStax Java ドライバのデフォルトは LOCAL_ONE。 本番で 「思ったより整合性が緩い」 事象の多くはこれが原因。 アプリケーション起動時に明示的に LOCAL_QUORUM 等を設定しましょう。

CqlSession.builder()
    .withLocalDatacenter("ap_northeast_1")
    .withConfigLoader(DriverConfigLoader.programmaticBuilder()
        .withString(DefaultDriverOption.REQUEST_CONSISTENCY, "LOCAL_QUORUM")
        .build())
    .build();

3. Hinted Handoff を 「整合性担保」 と誤解する

Hinted Handoff は 「一時的な不在ノードへの書き込みを後で届ける」 仕組みで、 整合性を保証するわけではない 。 Hint の保持期間 (max_hint_window_in_ms, 既定 3 時間) を越えると失われます。 Hint に頼る設計は危険。

4. Read Repair の負荷を侮らない

Read 時にレプリカ間で差分があれば、裏で修復を走らせます (dc_local_read_repair_chance)。 大規模クラスタでは Read Repair が無視できない負荷になるため、必要なら 0.0 に。


まとめ:

  • 本番は LOCAL_QUORUM 基本、R + W > RF を守る で 90% のユースケースはカバー- ALL は避け、EACH_QUORUM はクロス DC 強整合が明確に要る場合のみ
  • LWT (IF NOT EXISTS 等) は切り札として使い、乱用しない
  • 本番相当の RF で負荷テストを必ず行う

一貫性レベルは 「設定すれば終わり」 ではなく、ワークロード × 障害シナリオ とセットで検証する運用対象です。

関連記事