Как теорема CAP влияет на разделение таблиц для чтения и записи
Что проверяют
Понимаете ли вы, что CAP касается копий данных в сети, а не таблиц как таковых, и можете ли перевести теорию в поведение системы с репликами на чтение. Следом обычно спрашивают, как пользователь увидит собственную только что сделанную запись, если читает с реплики.
Как отвечать
Сначала поправьте формулу «выбери два из трёх». Сетевое разделение в распределённой системе неизбежно, и выбор возникает в момент разделения: отвечать всем (A) с риском устаревших данных или отказывать части запросов ради линеаризуемости (C). Вне разделения работает PACELC: выбор между задержкой и согласованностью.
Применительно к разделению чтения и записи:
- реплики на чтение: запись идёт на primary, чтение на реплики с асинхронной репликацией. Это выбор в пользу доступности и задержки, реплика отстаёт на время лага;
- чтение своих записей: после записи пользователя какое-то время читать с primary или передавать позицию журнала и ждать, пока реплика её догонит;
- синхронная репликация: в PostgreSQL
synchronous_commitиsynchronous_standby_names. Согласованность выше, но коммит ждёт реплику, и её отказ останавливает запись; - CQRS: отдельная модель для чтения (денормализованные таблицы, поисковый индекс) обновляется событиями через outbox или CDC. Согласованность итоговая, интерфейс должен это учитывать.
На Java маршрутизацию обычно делают через AbstractRoutingDataSource в Spring: @Transactional(readOnly = true) уходит на реплику, остальное на primary. Его оборачивают в LazyConnectionDataSourceProxy, иначе соединение берётся до того, как известны атрибуты транзакции.
Где спотыкаются
Применяют CAP к двум таблицам в одной базе. Внутри одного узла и одной транзакции согласованность обеспечивает ACID, CAP там ни при чём.
Путают C из CAP с C из ACID. В CAP это линеаризуемость реплик, в ACID это соблюдение ограничений целостности.
Выносят чтение на реплики и не думают о лаге. Пользователь сохраняет профиль, обновляет страницу и видит старые данные: это прямое следствие выбранного компромисса, и решение нужно назвать заранее.