.NET Tutorial
Senior6 мин чтенияВопрос 13 из 17

Что такое CAP-теорема применительно к БД?

Формулировка

Consistency:
каждое чтение видит последнюю запись

Availability:
каждый узел отвечает

Partition tolerance
разделение сети в распределённой
системе неизбежно

Что важнее, пока узлы
не видят друг друга?

CP — часть узлов отказывает
etcd, ZooKeeper, MongoDB (majority),
CockroachDB, Spanner

AP — данные временно расходятся
Cassandra, DynamoDB, CouchDB, DNS

CA — возможно только без разделения:
одиночный узел, не распределённая система

Consistency:
каждое чтение видит последнюю запись

Availability:
каждый узел отвечает

Partition tolerance
разделение сети в распределённой
системе неизбежно

Что важнее, пока узлы
не видят друг друга?

CP — часть узлов отказывает
etcd, ZooKeeper, MongoDB (majority),
CockroachDB, Spanner

AP — данные временно расходятся
Cassandra, DynamoDB, CouchDB, DNS

CA — возможно только без разделения:
одиночный узел, не распределённая система

CAP: выбор делается в момент разделения сети

Теорема (Брюер, 2000; доказательство Гилберта и Линч, 2002) говорит о моменте разделения сети. В нормальной работе система может быть и согласованной, и доступной.

Что происходит при разделении

Клиент 2Узел BУзел AКлиент 1связь между узлами потерянаCP: не могу подтвердить запись у B — отказ / ожиданиеAP: записываю локально, отвечаю OKCP: не уверен в актуальности — отказ (или только лидер отвечает)AP: отвечаю старым значением 1000связь восстановленаAP: синхронизация и разрешениеконфликтовзаписать balance = 500прочитать balance
Клиент 2Узел BУзел AКлиент 1связь между узлами потерянаCP: не могу подтвердить запись у B — отказ / ожиданиеAP: записываю локально, отвечаю OKCP: не уверен в актуальности — отказ (или только лидер отвечает)AP: отвечаю старым значением 1000связь восстановленаAP: синхронизация и разрешениеконфликтовзаписать balance = 500прочитать balance
Сеть разделилась: узлы не видят друг друга

CP-системы

Жертвуют доступностью: узлы, не попавшие в большинство (кворум), перестают принимать записи (или чтения). Пример — Raft/Paxos-консенсус: лидер должен получить подтверждение большинства.

  • etcd / Consul / ZooKeeper — хранилища конфигурации и координации; согласованность важнее.
  • MongoDB с writeConcern: majority и readConcern: majority/linearizable.
  • CockroachDB, YugabyteDB, Spanner — распределённые SQL-базы с консенсусом.

AP-системы

Отвечают всегда, но разные узлы могут вернуть разные данные. После восстановления связи — синхронизация и разрешение конфликтов:

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

Настраиваемая согласованность: кворумы

В Cassandra и DynamoDB согласованность выбирается на каждый запрос. При N репликах, W — число подтверждений записи, R — число реплик для чтения:

N = 3 реплики

Реплика 1

Реплика 2

Реплика 3

Запись: W = 2
(QUORUM)

Чтение: R = 2
(QUORUM)

R + W = 4 > 3:
хотя бы одна реплика
содержит свежую запись

N = 3 реплики

Реплика 1

Реплика 2

Реплика 3

Запись: W = 2
(QUORUM)

Чтение: R = 2
(QUORUM)

R + W = 4 > 3:
хотя бы одна реплика
содержит свежую запись

Кворум R + W > N гарантирует пересечение
Уровень Запись Чтение Свойства
ONE / ONE 1 реплика 1 реплика Максимальная доступность и скорость, возможны устаревшие чтения
QUORUM / QUORUM Большинство Большинство Сильная согласованность чтения своих записей, переживает отказ меньшинства
ALL Все — Любой отказ узла — запись невозможна

PACELC

да (P)

нет (Else)

Есть разделение сети?

A или C?

Latency или C?

PA: отвечать всегда

PC: согласованность

EL: быстрый ответ
(асинхронная репликация)

EC: ждать подтверждений
(синхронная репликация)

да (P)

нет (Else)

Есть разделение сети?

A или C?

Latency или C?

PA: отвечать всегда

PC: согласованность

EL: быстрый ответ
(асинхронная репликация)

EC: ждать подтверждений
(синхронная репликация)

PACELC: выбор есть всегда
Система Классификация PACELC
Cassandra, DynamoDB (по умолчанию) PA/EL — доступность и скорость
MongoDB (по умолчанию) PA/EC* (зависит от настроек write/read concern)
etcd, ZooKeeper, Spanner, CockroachDB PC/EC — согласованность всегда
PostgreSQL с асинхронной репликой При failover возможна потеря данных (EL); с синхронной — EC

Где это важно .NET-разработчику

  • Чтение с реплик (асинхронная репликация) — это уже eventual consistency: «прочитать свою запись» может не получиться.
  • Кэш (Redis перед БД) — ещё одна копия данных; инвалидация — задача согласованности.
  • Микросервисы со своими БД и событиями — система в целом AP-подобна: данные согласуются через события с задержкой.
  • Распределённые блокировки (Redis) — при разделении сети могут выдать блокировку двум клиентам; для строгих гарантий нужны CP-системы (etcd) и fencing-токены.

Вопросы на засыпку

Почему нельзя выбрать CA?

В распределённой системе нельзя гарантировать отсутствие сетевых разделений — это внешнее событие. Отказаться от P значит построить систему, которая при разделении ведёт себя непредсказуемо. «CA» честно только для одного узла, который не является распределённой системой.

Чем C в CAP отличается от C в ACID?

ACID-consistency — соблюдение ограничений целостности внутри одной БД. CAP-consistency — линеаризуемость: любое чтение возвращает результат последней завершённой записи, как если бы копия данных была одна.

Является ли реляционная БД CP или AP?

Одиночный сервер не распределён — CAP к нему в чистом виде не применяется. Кластер с синхронной репликацией и автоматическим failover ведёт себя как CP (при потере кворума запись недоступна), с асинхронными репликами для чтения — чтения AP-подобны (могут быть устаревшими).

Что такое eventual consistency и какие есть более сильные модели?

Eventual — если записи прекратятся, все реплики со временем придут к одному значению; гарантий «когда» нет. Сильнее: read-your-writes, monotonic reads, causal consistency (причинно связанные операции видны в правильном порядке), linearizability (строгая).

Итог

CAP напоминает: при разделении сети распределённая система выбирает между согласованностью и доступностью, а PACELC — что и без сбоев согласованность стоит задержки. Многие хранилища позволяют настраивать этот выбор на уровне запроса. Для разработчика важно понимать, где в его системе живут копии данных (реплики, кэши, сервисы) и какие гарантии они дают.