На прошлой неделе мы выяснили, что CDC — это инструмент, который читает журнал транзакций базы (WAL) и превращает изменения в поток событий. Но зачем это нужно микросервисам?
Проблема двойной записи (Dual Write Problem)
Представь, что твой сервис заказов должен сохранить заказ в БД и отправить событие в Kafka для сервиса аналитики.OrderCreated
Если ты сделаешь это прямо из кода (сохранил в БД -> отправил в Kafka), ты рискуешь нарваться на Двойную запись. Сеть может моргнуть в момент отправки в Kafka. В итоге в твоей БД заказ есть, а аналитика о нем не знает. Наступает рассинхрон (Inconsistency).
Выше мы разбирали паттерн Transactional Outbox. Давай посмотрим, как CDC может нам помочь.
- Приложение открывает транзакцию в БД.
- Сохраняет заказ в таблицу
.orders - В той же транзакции сохраняет событие в специальную таблицу
.outbox_events - Транзакция коммитится (обе записи либо проходят, либо откатываются).
- CDC в фоновом режиме читает лог БД, видит новую запись в
и гарантированно доставляет её в Kafka.outbox_events
CDC vs События приложения
CDC передает «сырые» изменения (что изменилось в таблице). События приложения передают бизнес-намерение (почему это изменилось).
- Когда выбирать CDC: Нужно просто синхронизировать данные между хранилищами (например, сбросить данные из Postgres в ElasticSearch или Redis).
- Когда выбирать события через событийную архитектуру: Событие содержит бизнес-контекст. Например, статус пользователя поменялся на
VIP. CDC скажет: «В столбце статус изменился 0 на 1». App Event скажет: «Пользователь купил премиум-подписку по промокоду NEWYEAR».
Антипаттерн CDC: Не используй CDC для таблиц с высокочастотными обновлениями (например, счетчик просмотров). Если счетчик обновился 10 000 раз, CDC отправит в очередь 10 000 отдельных сообщений (1, 2, 3...), что мгновенно положит сеть. Здесь лучше использовать батчинг или in-memory хранилища.