Strong Consistency: когда нужно
Strong Consistency (линейризуемость) — модель, при которой все операции выглядят так, словно выполняются мгновенно и последовательно в едином глобальном порядке, согласованном с реальным временем. Пользователь прочитает последнее подтвержденное значение, а два параллельных клиента не «обгонят» друг друга логически.
Строгая согласованность дает простую ментальную модель и защищает жесткие инварианты, но требует координации (кворумов/лидера), что повышает задержку и чувствительность к сетевым разделениям.
1) Когда Strong — обязателен
Финансы и расчеты
Балансы и списания: «двойная трата» недопустима.
Переводы и взаиморасчеты: одна и та же сумма не может быть проведена дважды.
Инвентарь и лимиты
Остатки товара/места в отеле/билеты: нельзя уходить в отрицательные значения.
Лимиты операций в единицу времени (кредитные лимиты, API-кредиты).
Уникальность и целостность
Уникальные логины/идентификаторы/правила дедупликации.
Инварианты на уровне домена: «в отделении должен дежурить ≥1 врач», «в очереди не может быть >N активных задач».
Аудит и неизменяемые журналы
События, служащие юридическим источником истины: порядок и полнота критичны.
Если нарушение инварианта несет неприемлемый бизнес-риск (потеря денег, санкции, утрата доверия) — выбирайте Strong Consistency.
2) Что именно «строгое»
Linearizability (операционный уровень): чтение видит самую последнюю успешную запись; времена уважены.
Serializable (транзакционный уровень): результат эквивалентен выполнению транзакций последовательно (может быть strong, но иногда реализован без жесткого real-time порядка).
Важная разница: Serializable защищает от аномалий уровня транзакций (phantom/write-skew), а Linearizable — про моментальность и порядок одиночных операций. Часто нужны оба свойства (например, деньги в БД + журнал событий).
3) Цена строгости: PACELC и CAP
PACELC: при разделении сети (P) приходится выбирать C (строгость) или A (доступность). Strong → CP: лучше отказать или заблокировать, чем нарушить инвариант. Когда разделения нет (EL), платим L — координацией/кворумами растет p95/p99.
Практика: strong для «ядра инвариантов», вокруг — быстрые проекции/кэши с eventual, чтобы не страдал UX.
4) Как достигают Strong Consistency
Лидерство и кворумы
Единственный лидер принимает записи; чтения — у лидера или по кворуму реплик.
Кворум `W` для записи и `R` для чтения с `R+W>N` повышает шансы читать «последнее».
Алгоритмы согласования
Raft/Paxos: лог репликации, подтверждения большинства, термин/индексы.
Синхронная репликация: запись подтверждается только после персистентности на кворуме.
Часы и порядок
TrueTime/Hybrid Logical Clocks (HLC): ограничение рассинхрона часов для безопасной глобальной сериализации.
Fence-токены/версионирование: защита от «утренних» лидеров и сплит-брейна.
Изоляция транзакций
Serializable (SI+ проверка конфликтов/локи по предикатам): защита от phantom/write-skew.
Strict-serializable: сериализуемость + линейризуемость относительно реального времени.
5) Мульти-регион: варианты и компромиссы
Глобальный лидер (CP)
Записи идут через один регион-лидер; чтения — локальные кэши/проекции или через лидера.
Плюсы: простая модель. Минусы: p95/RTT до лидера, при P — блокировки записей.
Региональные лидеры + синхронный кворум
Георасширенный кворум из нескольких регионов; каждая запись ждет подтверждений >50%.
Плюсы: без единой «узкой шеи», высокая устойчивость. Минусы: межконтинентальная латентность.
Geo-partitioning
Данные «домашние» для региона (тенант/юрисдикция); глобальные операции — через саги/агрегаты.
Плюсы: низкие задержки для локальных записей. Минусы: планирование границ данных.
6) Настройка R/W и чтений
Записи: `W=majority` — стандарт для strong.
Чтения:- «Самое свежее» — `R=majority` или чтение у лидера.
- Для снижения L — «stale-ok» чтения из реплик для второстепенных экранов (с явной маркировкой в UX).
- Read-repair / lease read: оптимизации без потери строгости при коротких арендах лидера.
7) Производительность и UX
Латентность: ориентируйтесь на RTT между клиентом и лидером/кворумом (межрегионально сотни мс).
Паттерн «write-strong, read-fast»: strong на записи + кэш/проекции на чтениях, с RYW для автора.
Batch/пакеты: группируйте записи, но следите за хвостовой латентностью.
Контуры деградации: при инциденте — read-only, честные статусы, запрет опасных мутаций.
8) Наблюдаемость strict-пути
Метрики
p50/p95/p99 latency: write-кворум, read-кворум, лидерские чтения.
Успешность кворумов, повторы/откаты, смены лидера.
Репликационный лаг (ожидаемо мал, но мониторить обязательно).
Доля «стейл» чтений (если включены).
Трейсинг
Спаны: «принятие лидером», «репликация», «коммит кворума».
Теги: `term`, `leader_id`, `quorum_size`, `region`.
Алерты
Рост p95/p99, частая переизбрания лидера, кворум-timeouts, split-brain индикаторы.
9) Тесты и хаос
Jepsen-подобные: сетевые разделения, задержки, дропы, clock-skew.
Safety-инварианты: невозможность двойной траты/отрицательных остатков/двойного бронирования.
Лидерство: отказ лидера, перевыборы под нагрузкой, fence-токены.
Согласованность чтений: чтение сразу после записи должно видеть «новое» (RYW/linearizable read).
10) Плейбуки инцидентов
Потеря кворума: переключить в read-only, оповестить клиентов, направить запись в «домашний» регион при наличии geo-partitioning.
Рост латентности межрегионально: временно понизить объем строгих записей (миграция части потоков в очереди/проекции), локализовать трафик.
Флап лидера: увеличить таймауты выборов, проверить сети/часовые дрейфы/GC-паузы.
Split-brain: включить fence-токены/lease-проверки, остановить старых лидеров на уровне оператора.
11) Типичные ошибки
Требовать Strong «везде»: взрыв латентности и стоимости вместо фокусировки на инвариантах.
Пытаться быть CA при реальных разделениях: в момент P система все равно делает выбор, часто неявно.
Dual-write в разные регионы без саг/координатора: фантомы и потеря инвариантов.
Отсутствие RYW: пользователь не видит свою только что записанную сущность — падение доверия.
Игнорирование часов: без HLC/TrueTime-границ легко получить «прыгающее» время и гонки.
Нет плана деградации: при P начинаются хаотичные частичные сбои.
12) Быстрые решения (рецепты)
Платежи/балансы: лидер + majority-кворум; транзакции strict-serializable; короткие таймауты, жесткий отказ при P.
Бронирование (места/слоты): write-strong через лидер, чтения — кэш с RYW; TTL-резервы + TCC.
Глобальный SaaS: geo-partition по `tenant/region`; строгие операции в домашнем регионе, отчеты/поиск — через проекции.
Аудит/журнал: append-only CP-журнал; чтения можно кешировать, но верифицировать контрольными точками.
13) Чек-лист перед продом
- Выписаны инварианты, требующие strong; остальное — в AP/проекции.
- Выбран режим: единый лидер / кворум межрегионально / geo-partition.
- Настроены `W=majority`, `R=leader|majority` для критичных путей.
- Обеспечены RYW/monotonic для UX; явно помечены «stale-ok» чтения.
- Включены метрики кворума, лагов, латентностей; алерты на p95/p99 и переизбрания.
- Есть degrade-план: read-only, отключение опасных мутаций, очереди на «после шторма».
- Хаос-тесты: разделения, clock-skew, отказ лидера; проверены safety-инварианты.
- Документация контрактов: что строго, что «может отставать», коммуникация для продукта/поддержки.
Заключение
Strong Consistency — инструмент защиты истины там, где ошибка неприемлема. Применяйте ее точечно вокруг жестких инвариантов, осознанно платя за координацию латентностью и доступностью в штормы. Комбинируйте: CP-ядро для критичного, AP-чтения и проекции для скорости. С правильной телеметрией, деградацией и тестами вы сохраните и корректность, и пользовательский опыт.