Гарантии доставки
Гарантия доставки отвечает на вопрос: может ли сообщение потеряться или обработаться дважды. Это критичный выбор — для платежей “дважды” недопустимо, для уведомлений о новой публикации — не страшно.
| Гарантия | Что значит | Риск |
|---|---|---|
| At-most-once | сообщение доставится максимум один раз | может потеряться |
| At-least-once | сообщение доставится минимум один раз | может обработаться дважды |
| Exactly-once | сообщение обработается ровно один раз | самая сложная и дорогая гарантия |
Копнуть глубже
At-least-once — самая частая гарантия на практике. Consumer подтверждает (commit) offset после успешной обработки сообщения — если он упадёт между обработкой и подтверждением, при перезапуске обработает это же сообщение заново. Это безопаснее, чем потерять сообщение, но требует, чтобы обработка была идемпотентной (см. тему «Идемпотентность и безопасность методов») — повторная обработка не должна приводить к двойному эффекту (например, двойному списанию денег).
Как добиться идемпотентности на практике — обычно через уникальный id сообщения/операции, который проверяется перед обработкой:
void processPayment(PaymentEvent event) {
if (paymentRepository.existsById(event.getId())) {
return; // уже обработали — пропускаем повтор
}
// реальная обработка платежа
}
Exactly-once в Kafka технически возможен (через транзакционный producer + идемпотентный producer), но добавляет существенные накладные расходы и сложность настройки — на практике большинство систем выбирают at-least-once + идемпотентность на стороне обработчика, это даёт тот же практический эффект проще и дешевле.
• почему at-least-once требует идемпотентной обработки на стороне consumer'а (если дошёл до 3-го слоя).