В проектировании есть классическая проблема dual write: нужно обновить несколько мест.
Возможные сценарии отказов
Сценарий 1: Успешная запись в БД + отказ Kafka
- Places Service успешно сохраняет данные о заведении
- Kafka недоступна или происходит network failure
- Событие теряется, downstream сервисы не получают уведомление
- Результат: система в inconsistent состоянии
Сценарий 2: Отказ БД + успешная отправка в Kafka
- Событие успешно отправлено в Kafka
- Запрос в PostgreSQL упал
- Результат: downstream сервисы получили событие о несуществующем изменении
Этап 1: обновляем данные в PG и в outbox через транзакцию. Outbox может быть как внутри одной БД, так и в рамках отдельной БД.
Ниже SQL пример. В коде это также делается через транзакцию
BEGIN TRANSACTION;
-- Обновляем основную таблицу
UPDATE places SET name = 'New Name' WHERE id = 123;
-- Записываем событие в outbox
INSERT INTO outbox (event_type, payload, aggregate_id)
VALUES ('PlaceUpdated', '{"id": 123, "name": "New Name"}', 123);
COMMIT;
Этап 2: вычитываем из outbox и пишем в Kafka
Этап 3: чистим outbox
💡Как доставлять данные из outbox в Kafka?
- Можно через отдельный worker
- Можно через CDC
Важно помнить, что мы выбираем семантику at-least-once. То есть на стороне Geo-Service нам нужно будет проверять на дубли — идемпотентность.