Урок по треку System design 8 мин

Консистентность, CAP и распределённые транзакции

CAP и PACELC, модели консистентности, кворумы, распределённые транзакции и саги.

Когда данные лежат на нескольких узлах, появляется вопрос: что увидит клиент, если узлы расходятся или связь между ними пропала.

CAP-теорема

В распределённой системе при сетевом разделении (Partition) нельзя одновременно гарантировать:

  • Consistency (линеаризуемость): любое чтение видит последнюю запись.
  • Availability: каждый запрос к живому узлу получает ответ (не ошибку).

Разделение сети в распределённой системе неизбежно, поэтому реальный выбор: при разделении жертвуем консистентностью (AP) или доступностью (CP). Без разделения можно иметь и то, и другое.

Примеры: системы с кворумом и лидером (etcd, ZooKeeper) ведут себя как CP: без большинства узлов запись отклоняется. Cassandra и DynamoDB по умолчанию ближе к AP и eventual consistency, хотя уровень настраивается.

PACELC

Уточняет CAP: если есть разделение (P), выбираем между A и C; иначе (Else) выбираем между задержкой (Latency) и консистентностью (Consistency). Синхронная репликация даёт консистентность ценой задержки.

Модели консистентности

  • Строгая (линеаризуемость): как будто одна копия данных.
  • Read-your-writes: пользователь видит свои записи.
  • Монотонное чтение: не видим данные «откатывающимися назад».
  • Причинная: если B следует из A, все видят A раньше B (ответ после вопроса).
  • Eventual consistency: если записи прекратятся, реплики со временем сойдутся. Лайки, счётчики просмотров, ленты.

Кворумы

N реплик, запись подтверждается W узлами, чтение опрашивает R узлов. Если R + W > N, множества пересекаются и чтение увидит последнюю подтверждённую запись. Типично N=3, W=2, R=2. W=1, R=1 даёт скорость, но возможны устаревшие чтения.

Распределённые транзакции

2PC (двухфазный коммит): координатор спрашивает всех «готовы?», затем говорит «коммит». Даёт атомарность, но блокирует ресурсы, и при падении координатора участники зависают. В микросервисах применяют редко.

Сага: последовательность локальных транзакций, у каждой есть компенсирующее действие. Например: создать заказ → списать деньги → зарезервировать товар. Если резерв не удался, выполняются компенсации: вернуть деньги, отменить заказ. Два стиля:

  • хореография: сервисы реагируют на события друг друга;
  • оркестрация: центральный оркестратор говорит, кому что делать (проще отлаживать).

Сага не даёт изоляции: промежуточные состояния видны, поэтому вводят статусы вроде «ожидает оплаты».

Идемпотентность и ключи идемпотентности

Клиент отправляет Idempotency-Key с запросом платежа. Сервер запоминает результат по ключу, и повтор после таймаута не спишет деньги дважды. Это стандартная практика платёжных API.

Конфликты при записи в несколько мест

  • Last write wins по метке времени: просто, но теряет данные и зависит от часов.
  • Векторные часы: обнаруживают конкурирующие версии.
  • CRDT: структуры, которые сливаются без конфликтов (счётчики, множества), используются в совместном редактировании.

Частые ошибки

  • Говорить «выбираем CA» для распределённой системы.
  • Путать C из CAP с C из ACID: в ACID это соблюдение ограничений целостности, а не свежесть реплик.
  • Использовать 2PC между десятком микросервисов.
  • Забыть про компенсации в саге.

Что спросят на собесе

  • Объясните CAP на примере.
  • Что такое eventual consistency и где она допустима.
  • Как сделать перевод денег между сервисами без 2PC.
  • Как работают кворумы и что значит R + W > N.
  • Как защититься от двойного списания.

Закрепите за 5 минут

После урока в тренажёре 3-5 проверочных вопросов, дальше модуль уходит в повторения.