Продюсер получил подтверждение публикации, но брокер отключился до записи сообщения на диск. Какую гарантию должен обеспечить брокер, чтобы подтверждение означало сохранность сообщения?
Подтверждение публикации должно выдаваться только после устойчивой фиксации сообщения согласно заявленной модели отказов: например, после записи на надёжный носитель или после подтверждения кворумом реплик. Простое помещение сообщения в память брокера не является гарантией сохранности при его отключении.
Нужно явно определить, какой отказ должен переживаться: перезапуск процесса, потеря узла, отказ диска или потеря площадки. Чем сильнее гарантия, тем выше задержка публикации и стоимость хранения.
Ранние очереди часто подтверждали сообщение сразу после приёма в память. Это давало высокую производительность, но сбой процесса или питания мог уничтожить уже подтверждённые сообщения.
Появление дисковых журналов, журналов предварительной записи и репликации позволило отделить быстрый приём данных от устойчивого коммита. Это решает проблему ложного успеха, когда клиент считает сообщение принятым, хотя после отказа оно исчезает.
Подтверждение — это обещание брокера клиенту. Если оно означает только «сообщение принято текущим процессом», то после сбоя клиент не знает, нужно ли публиковать его повторно.
Повторная публикация может создать дубликат, а отсутствие повтора — потерю сообщения. Поэтому подтверждение должно быть связано с чётким состоянием хранения, которое переживает предусмотренный отказ.
Запись только в память опасна при перезапуске процесса. Запись на диск одного узла защищает от некоторых программных сбоев, но не обязательно от отказа самого узла, диска или площадки.
Брокер должен отправлять подтверждение после durable commit — момента, когда сообщение нельзя потерять при отказах, входящих в заявленную модель надёжности. Для одного узла это обычно означает успешную фиксацию на устойчивом носителе; для кластера — подтверждение необходимого числа реплик с устойчивым состоянием.
Репликация сама по себе недостаточна. Если сообщение попало в память нескольких узлов, но ни один ещё не зафиксировал его надёжно, одновременный сбой питания может привести к потере. Аналогично, подтверждение одного узла не гарантирует сохранность при потере этого узла.
Кворум должен быть выбран относительно допустимого числа отказов. Если система должна пережить потерю одного узла, подтверждение обычно связывают с таким набором реплик, который гарантирует наличие сообщения хотя бы в одной оставшейся исправной реплике. Точная схема зависит от протокола репликации и правил выбора нового лидера.
Важно отличать подтверждение публикации от подтверждения обработки потребителем. Первое отвечает за сохранность сообщения в брокере, второе — за завершение бизнес-операции. Даже надёжно сохранённое сообщение может быть доставлено повторно после сбоя потребителя, поэтому обработчик обычно должен быть идемпотентным или использовать дедупликацию.
Устойчивое подтверждение имеет цену: фиксация на диске и ожидание реплик увеличивают задержку, а синхронная репликация снижает доступность при недоступности необходимого кворума. Ослабление гарантии повышает пропускную способность, но допускает потерю подтверждённых сообщений при более широком отказе.
Сервис заказов публикует событие о создании заказа. Брокер отвечает об успехе сразу после помещения события в память лидера, после чего узел теряет питание. Событие исчезает, а сервис уже не повторяет публикацию: downstream-сервис не создаёт резервирование товара.
Рассматривались три варианта. Подтверждать из памяти было бы самым быстрым, но не защищало бы от перезапуска. Подтверждать после записи на диск защищало бы от потери процесса, однако не от отказа узла. Подтверждать после устойчивой фиксации на требуемом наборе реплик увеличивало бы задержку и могло временно блокировать публикацию при потере кворума.
Выбран третий вариант: подтверждение выдаётся после выполнения политики устойчивой фиксации, рассчитанной на отказ одного узла. Для потребителей отдельно сохраняется идемпотентность по идентификатору события, поскольку сбой после доставки, но до подтверждения обработки всё ещё может вызвать повторную доставку.
Результат: отключение одного брокера больше не приводит к потере подтверждённых событий. Компромисс — более высокая задержка публикации и временная недоступность записи при недостаточном числе исправных реплик.
Нет, пока не определено, какие отказы должна переживать система. Такая запись может защитить от перезапуска процесса, но не обязательно от отказа диска, узла или площадки. Для защиты от потери узла требуется репликация с правилом подтверждения, обеспечивающим наличие сообщения после выбора нового рабочего узла.
Нужно учитывать, что именно подтверждали реплики: получение в памяти, запись в журнал или устойчивую фиксацию. Кроме того, новый лидер должен выбирать состояние по протоколу, сохраняющему записи, подтверждённые требуемым кворумом. Если выбор лидера или репликация реализованы неправильно, формальный кворум без корректного recovery-протокола не даёт обещанной гарантии.
Потому что публикация и обработка — разные этапы. Потребитель может выполнить бизнес-операцию, упасть до отправки подтверждения, после чего брокер доставит сообщение повторно. Для защиты применяют идемпотентные операции, уникальный идентификатор события с дедупликацией или транзакционную связку обработки с записью результата; это не заменяет устойчивую фиксацию сообщения, а решает другую проблему.