Обновить

Комментарии 6

  1. Сообщения должны быть идемпотентны. Финансовые транзакции с кодом ФТ, статусами и пр.

  2. Коммит в продюсере должен быть после получения ответа от очереди, что сообщение принято.

2 А если коммит не пройдет?

Если транзакция откатится в момент, когда kafka вернет ок - будет ненужное сообщение. Но, повторяю (и автор это указывает), система должна обеспечивать идемпотентность. Сообщения должны говорить не "сделай то-то", "добавь сто рублей на счет", а "приведи систему в такое-то состояние", "укажи, что количество товара сейчас, на столько-то часов, столько минут, секунд, такое-то".

Здесь https://www.litres.ru/book/gven-shapira/apache-kafka-potokovaya-obrabotka-i-analiz-dannyh-pdf-epub-42225434/ все хорошо рассмотрено.

Таблица outbox и нужна, чтобы присвоить идентификатор для транзакции (проводке) и дальше идемпотентность будет опираться на этот идентификатор.

Не указал про консьюмера, но там тоже проблема решается идемпотентностью, и тем, что консьюмер отправляет сигнал кафке о том, что сообщение потреблено (сдвинуть указатель) только после фиксации в своей базе.

Что-то я не понял пользы на вашем примере:

Наивный вариант:

Наивным решением было бы "сначала запишем в БД, а потом отправим в брокер", однако такое решение ломается при сбоях, если процесс упадет между этими двумя шагами, то мы либо потеряем событие, либо отправим дубль.

Вариант с очередью:

  1. Удалять обработанные события: меньше места в БД, но теряется история.

  2. Хранить и помечать статусом (например, SENT): есть аудит, но таблица будет расти и ее нужно архивировать/очищать.


Transactional Outbox гарантирует доставку at-least-once (хотя бы один раз).


Т.е. в обоих вариантах отправим дубль. И если в первый вариант добавить в БД флаг SENT
и делать повторы до успеха, то будет та же доставка at-least-once, но без внешних очередей.

Вообще смысл этого паттерна не в том, чтобы избежать дублей (все таки это at-least-once паттерн), а в том, чтобы не потерять событие и не получить рассинхрон при сбое. В данном случае разница между "наивным решением" и описанном в статье в атомарности записи и контролируемом ретрае.

Например, если сервис упал после записи в БД и до публикации - событие будет потеряно навсегда. Если упал после публикации и до коммита в БД, то можем получить фантомное событие, т.е. из брокера оно пришло, а в БД его нет.

По поводу outbox таблицы без брокера - это тоже валидный вариант, в данной статье приведен лишь один из вариантов реализации, в котором используется асинхронная обработка. Такой вариант нужен, когда событие может быть обработано не сразу. Подход с брокером может помочь, когда нам событие нужно обрабатывать сразу в нескольких сервисов, которые будут читать этот топик.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации