Quorum reads/writes concept page. Leaderless replica set N=3 (r1, r2, r3), client → coordinator → replicas pattern. Shows W+R>N strong consistency formula, ONE/QUORUM/ALL/LOCAL_QUORUM tunable consistency, sloppy quorum + hinted handoff during partition. Three scenarios: QUORUM strong (W=2,R=2,N=3), ONE/ONE fast-but-stale, sloppy quorum with hinted handoff replay after partition heal. Two ADRs: tunable W/R per workload, sloppy vs strict quorum trade-off.
Quorum reads/writes — техника тонкой настройки consistency vs latency в leaderless репликации (Cassandra, DynamoDB, Riak). Данные хранятся на N replicas. Клиент сам выбирает: ждать ack от W replicas при записи и опрашивать R replicas при чтении. Формула W + R > N гарантирует strong consistency: read quorum пересекается с write quorum хотя бы в одной replica, которая видела последнюю запись.
Представь голосование комитета из N человек. На записи ты должен убедить W членов проголосовать «за». На чтении ты опрашиваешь R членов и выбираешь самый свежий ответ (по timestamp / vector clock). Если W + R > N, то любые два таких подмножества обязательно пересекаются — нельзя «выбрать W=2 из 3 и потом другие R=2 из 3 без пересечения». Это pigeonhole-гарантия: писатель и читатель обречены встретиться хотя бы на одной replica.
При W + R ≤ N пересечения может не быть → eventual consistency: writer и reader могут поговорить с разными подмножествами, читатель увидит старое значение, пока anti-entropy/read-repair не догонит.
Три сценария показывают разные W/R режимы: balanced QUORUM, fast-but-stale ONE/ONE, и sloppy quorum при partition с hinted handoff.
1. W=2, R=2, N=3 → strong consistency (QUORUM). Write идёт fan-out на все 3 replicas, coordinator отвечает клиенту после 2-х ack (~5ms, latency = max из двух самых быстрых). Третья replica догоняет в фоне — клиента это уже не блокирует. Read опрашивает 2 из 3 replicas, обе возвращают одинаковый timestamp → coordinator отвечает свежим значением. Pigeonhole-гарантия: из 3 replicas write попал в 2, read опрашивает 2 → хотя бы 1 пересечение → читатель видит свежий write.
2. W=1, R=1 → fast но stale (ONE/ONE). Write возвращается за ~1ms — первая же replica ack, остальные пишут async. Read сразу после — coordinator маршрутизирует на случайную replica (token-aware/snitch). Если попал на r3, куда write ещё не доехал → возвращается старое значение. W+R=2 ≤ N=3, overlap-гарантии нет. Через миллисекунды hinted handoff и read repair выровняют, но в моменте клиент видит stale. Подходит для view-counters, metrics, аналитики; ломает balance/inventory/auth.
3. Sloppy quorum + hinted handoff при partition. r2 unreachable (network split, GC pause, OOM). Coordinator всё равно принимает write на r1 + r3, формально достигает W=2, отвечает клиенту 200 OK. Дополнительно сохраняет hint — «write X для r2, отдай когда поднимется». Когда r2 возвращается через ~30s, coordinator реплеит hint, anti-entropy подчищает остатки через Merkle tree. Trade-off: write availability сохраняется во время partition, но CL=ONE read на r2 в окне 30s вернёт stale. CL=QUORUM read остаётся корректным: r1+r3 знают новое, любые 2 из 3 включают одного из них.
ADR-001. Tunable W/R под workload. Default — QUORUM (W=2, R=2 при N=3): и writes и reads переживают потерю одной replica, latency = P50 из двух самых быстрых, W+R=4>N=3 даёт strong consistency. Для analytics с tolerance к stale → ONE/ONE ради latency. Для read-heavy social feeds → (W=3, R=1) — чтения мгновенные с любой replica, но writes ждут самого медленного и любая failed replica блокирует write. Multi-DC: всегда LOCAL_QUORUM для writes (не ждать cross-region link 100+ms), EACH_QUORUM только для финансов где нужно подтверждение в каждом DC. ALL — никогда (любой fail убивает availability).
ADR-002. Sloppy quorum + hinted handoff vs strict. Sloppy (Dynamo-style, Cassandra default) — coordinator принимает write на ЛЮБУЮ доступную ноду, помечает hint, реплеит при восстановлении. Writes никогда не блокируются partition (AP). Но W+R>N больше не гарантирует strong reads — write мог уйти на чужую ноду, не входящую в read quorum. Strict (Cassandra с pw флагом, Riak primary writes) — write fails с UnavailableException, если W primary replicas недоступны. Гарантия consistency, но availability падает (CP). Правило: для критичных данных (deny-list, billing, auth) → strict QUORUM с retry на app-уровне. Для idempotent metrics/events → sloppy для max availability.
ONE, TWO, THREE, QUORUM (N/2+1), LOCAL_QUORUM, EACH_QUORUM, ALL, LOCAL_ONE, ANY (write принимается даже только hint). Hinted handoff TTL 3 часа по умолчанию.ConsistentRead=false (default, eventual, ~1 RCU) vs ConsistentRead=true (strongly consistent, 2 RCU, выше latency). Под капотом — quorum semantics, но AWS прячет N/W/R от клиента.none / majority / majority_persisted_to_active / persisted_to_majority — аналог W при добавленной семантике fsync.writeConcern: {w: "majority"} и readConcern: "majority" дают аналог W+R>N через leader-based replication.