Кворумы: чтение конфигов и кода
Читайте реальные конфигурации уровней согласованности и проверку пересечения кворума, предсказывайте, гарантирует ли каждая последнюю запись, и выбирайте самый рычажный фикс.
Баги кворума живут в строках уровня согласованности вашего кода доступа к данным, а не в самой базе. Прочитайте каждый конфиг и сниппет, сделайте арифметику R + W против N и выберите фикс, который сделал бы senior-инженер первым.
Отработайте цикл, который вы запускаете, когда прилетает тикет про устаревшее чтение: найдите R и W в коде, проверьте, действительно ли R + W > N для replication factor этого keyspace, и потянитесь к фиксу, который восстанавливает пересечение, а не прячет его.
Сниппет 1 — раздельная согласованность чтения и записи
# keyspace создан WITH replication = { 'class': 'SimpleStrategy', 'replication_factor': 3 }
session.execute(
SimpleStatement(
"UPDATE accounts SET payout = %s WHERE id = %s",
consistency_level=ConsistencyLevel.QUORUM, # W = 2 при RF=3
),
(new_payout, account_id),
)
balance = session.execute(
SimpleStatement(
"SELECT payout FROM accounts WHERE id = %s",
consistency_level=ConsistencyLevel.ONE, # R = 1
),
(account_id,),
).one()
Запись — QUORUM (W=2), а чтение — ONE (R=1) при RF=3. Гарантирует ли это, что чтение увидит последний payout, и в чём фикс?
Сниппет 2 — хелпер проверки пересечения
def guarantees_latest_read(n: int, r: int, w: int) -> bool:
# True тогда и только тогда, когда чтение гарантированно видит последнюю запись
return r + w > n
# вызов для нового keyspace, RF = 4
print(guarantees_latest_read(n=4, r=2, w=2)) # что напечатает и безопасно ли это?
При N=4 с R=2, W=2 что напечатает guarantees_latest_read и верный ли это ответ?
Сниппет 3 — путь записи sloppy quorum
def write_quorum(coordinator, key, value, n=3, w=2):
home = coordinator.preference_list(key, n) # N назначенных реплик
live = [node for node in home if node.is_reachable()]
acks = [node.store(key, value) for node in live]
if len(acks) >= w:
return "OK (strict quorum)"
# назначенных реплик недостаточно -> sloppy quorum
for sub in coordinator.next_healthy_ring_nodes():
acks.append(sub.store_hint(key, value, intended_owner=...))
if len(acks) >= w:
return "OK (sloppy quorum)" # подтверждено, но где?
return "FAIL"
Когда это возвращает 'OK (sloppy quorum)' во время partition, каково следствие для согласованности конкурентного строгого QUORUM-чтения с домашних реплик?
Сниппет 4 — флаг чтения DynamoDB
# DynamoDB, репликация управляется; согласованность чтения задаётся на запрос
resp = table.get_item(
Key={"id": account_id},
ConsistentRead=False, # по умолчанию: итоговая согласованность
)
Чтение баланса использует ConsistentRead=False. Что даёт переключение на True и чего это стоит — в терминах кворума?
Любой баг кворума читается одинаково: найдите R и W в строках уровня согласованности, найдите N из replication factor keyspace и проверьте R + W > N со СТРОГИМ неравенством — R=1-чтения за QUORUM-записями и любой чётный сплит вроде R=2,W=2 при N=4 — классические ловушки, дающие в сумме N и тихо допускающие устаревшие чтения. Фикс, восстанавливающий пересечение (обычно поднятие уровня ЧТЕНИЯ), лучше фиксов, которые его прячут. Sloppy quorum (sloppy quorum — слабый кворум, принимающий ack от узлов-заместителей вместо назначенных реплик) подтверждает через держателей hint вне множества чтения, поэтому его ‘OK’ приостанавливает пересечение во время partition; а управляемые хранилища выставляют ту же ручку как ConsistentRead, где strong-чтения стоят примерно 2x capacity за гарантию. Теперь, увидев настройку уровня согласованности в коде, вы автоматически спросите: какой RF у этого keyspace и выбивается ли R + W за порог?
Что-то непонятно?
Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.