Перейти к основному содержимому

Apache Kafka: гарантии доставки | защита от дублей | партиции и масштабирование

Три типа доставки сообщений

At most once

Продюсер отправляет сообщение и не ждет подтверждения. При сбое данные могут потеряться.

  • Пример: отправка логов, где потеря одной записи некритична. Или сервисы отправляют метрики в Kafka без ожидания подтверждения
  • Как работает: продюсер не ждёт подтверждения от брокера (acks=0), консьюмер сразу обновляет офсет

At least once

Продюсер отправляет сообщение, ждет подтверждения. При сбое может отправить повторно, из-за чего появляются дубли.

  • Пример: платёжная система, где потеря недопустима, но дубликаты можно обработать
  • Как работает: продюсер ждёт подтверждения (acks=all), консьюмер обновляет офсет только после обработки

Exactly once

Идеальная гарантия: без потерь и дублей. Kafka поддерживает механизм Transactional Producer.

  • Реализуется через:
    • Идемпотентные продюсеры (Kafka 0.11+) – подавление дублей на стороне брокера (см ниже)
    • Транзакции между продюсером и консьюмером (read-process-write цикл) (см ниже)
  • Ограничения: работает только в рамках одного кластера Kafka

Пример: Обработка заказов в e-commerce, заказ фиксируется в БД + отправляется событие в Kafka в одной транзакции Важно: на практике exactly once сложно обеспечить. Даже если Kafka сохраняет сообщение один раз, потребляющая система может ошибиться (например, дважды обработать запись). Нужен строгий контроль на всех этапах архитектуры

Гарантии доставки:

  • At most once → без подтверждения → возможны потери
  • At least once → с подтверждением → возможны дубли
  • Exactly once → транзакции + идемпотентность → нет потерь и дублей, но дорого и сложно

Защита от дублей

При использовании At least once возможны дубли, необходимо предусматривать их обработку

1. Индекс уникальности

Можно настроить ключи сообщений так, чтобы консьюмер сохранял только уникальные значения.

  • Продюсер генерирует message_id (UUID или хэш содержимого)
  • Брокер или БД консьюмера проверяет уникальность перед записью

Пример: База заказов с уникальным индексом по order_id → повторная запись невозможна

2. Паттерн Outbox

  • При обновлении данных сервис сохраняет событие в отдельную таблицу Outbox вместе с основной записью
  • Фоновый процесс читает события из Outbox и отправляет их в Kafka

Пример: интернет-магазин записывает заказ в основную таблицу и событие "OrderCreated" в Outbox. Затем отдельный процесс отправляет событие в Kafka

3. Паттерн Inbox

Используется на стороне консьюмера

  • Все события сохраняются в отдельную таблицу Inbox перед обработкой
  • При сбое необработанные события можно переобработать без риска дублирования

Пример: сервис оплаты принимает событие "OrderPaid", сохраняет его в Inbox, затем подтверждает обработку

Inbox и Outbox паттерны часто применяются вместе, чтобы обеспечить надёжность и идемпотентность при взаимодействии между микросервисами через Kafka

Гарантии доставки

Гарантии продюсера

acks = настройка количества подтверждений продюсером

acks=0

  • Продюсер отправляет сообщение и не ждёт подтверждения
  • Возможные потери данных при сбое сети или брокера
  • Высокая производительность, низкая надёжность

acks=1

  • Брокер-лидер партиции подтверждает получение сообщения
  • Если лидер упадёт до синхронизации с фолловерами (репликации), сообщение теряется
  • Баланс между производительностью и надёжностью

acks=all

  • Сообщение считается принятым только после подтверждения от всех синхронных реплик
  • Максимальная надёжность, минимизация риска потерь при сбоях
  • Может увеличивать задержку на запись

Идемпотентные продюсеры

Продюсер присваивает каждой записи уникальный идентификатор (Producer ID + Sequence Number).
Если запись отправляется повторно (например, из-за сетевого сбоя), брокер распознает дубликат и не сохраняет его второй раз.
Настройка: enable.idempotence=true у продюсера

Транзакции в Kafka

Позволяет обрабатывать несколько сообщений в рамках одной атомарной транзакции:

  • Продюсер начинает транзакцию → отправляет события → фиксирует транзакцию (commit)
  • Если происходит сбой → транзакция откатывается (abort) и сообщения не попадают в топики
  • Используется вместе с идемпотентностью для достижения exactly once

Совмещение с базой данных

Чтобы обеспечить консистентность между базой и сообщениями в Kafka, применяют паттерн Outbox + транзакционные обновления.
Либо используют distributed transaction менеджеры (например, двухфазный коммит, но он увеличивает сложность)

Партиции и масштабирование

Партиция — минимальная единица хранения и обработки сообщений в Kafka.
Масштабирование Kafka-кластера напрямую зависит от числа партиций.

Связь: партиции → консьюмеры → сервисы

  • Партиция может быть одновременно прочитана только одним консьюмером в группе
  • Консьюмер — это отдельный процесс или поток приложения, читающий данные из Kafka
  • Сервис — приложение / микросервис, который внутри себя запускает одного или несколько консьюмеров
  • Каждый экземпляр сервиса (или процесс) фактически становится одним консьюмером Kafka

Важно

  • Чтение и запись могут происходить параллельно по количеству партиций → Чем больше партиций, тем выше параллелизм обработки
  • Порядок сообщений сохраняется только внутри одной партиции

Пример связи "партиции-консьюмеры"

  • Есть сервис BillingService, который обрабатывает события оплат
  • Запущено 10 инстансов BillingService (например, 10 подов в Kubernetes)
  • Топик для оплат имеет 3 партиции
  • Каждый экземпляр подключается к Kafka в составе одной группы консьюмеров (billing-consumer-group)

Если топик имеет только 3 партиции, то реально читать данные смогут только 3 экземпляра, а остальные 7 будут простаивать.

Итог: даже если сервисов запущено больше, чем партиций, работать будут только столько консьюмеров, сколько есть партиций

Почему важно количество партиций

  • Если партиций мало → масштабировать обработку за счёт увеличения количества сервисов не получится
  • Если партиций много → можно масштабировать консьюмеров горизонтально (новые инстансы будут получать работу)

Как проектировать партиции в Kafka

  • Одна партиция — один активный консьюмер в группе
  • Число партиций должно быть ≥ планируемого числа консьюмеров
  • Для сохранения порядка событий используйте ключи при отправке
  • Больше партиций → выше параллелизм → выше скорость обработки
  • Но слишком много партиций увеличивает нагрузку на брокеры (балансируйте)
  • Можно изначально планировать 1,5–2× больше партиций, чем текущее количество консьюмеров (с запасом на рост нагрузки)

Порядок доставки сообщений

Kafka сохраняет порядок внутри одной партиции (FIFO — First In, First Out).
Между разными партициями порядок не гарантируется.

Если важен строгий порядок, все связанные сообщения нужно направлять в одну партицию с использованием ключа (message key).
При использовании round-robin распределения без ключа порядок теряется.

Примеры порядка доставки

  • Заказы по одному пользователю (user_id) всегда направляются в одну партицию → сохранение порядка операций
  • События мониторинга отправляются без привязки к ключу → допустима потеря порядка
  • В финансовых транзакциях: каждое событие по конкретному счёту (account_id) попадает в одну партицию для строгого порядка операций
  • Все данные с одного устройства идут в одну партицию (device_id), чтобы сохранить последовательность событий

Примеры подходов при проектировании систем

  • Для критичных данных: использовать acks=all и идемпотентный продюсер
  • Для обеспечения порядка: всегда указывать ключ сообщения при отправке
  • Для защиты от дублей: комбинировать использование message_id, паттернов Inbox/Outbox и проверку уникальности на уровне базы данных
  • Для фоновой или некритичной передачи данных: допускается использование acks=1

Материалы

  1. Введение в Apache Kafka для системных аналитиков и проектировщиков интеграций
  2. Гарантии доставки сообщений в Kafka
  3. Синхронная и асинхронная отправка сообщений в Apache Kafka
  4. Выстрелил и забыл: 3 основные стратегии отправки сообщений в Kafka
  5. Что такое гарантия доставки сообщений или как избавиться от дублей и потерь в Apache Kafka и других Big Data брокерах
  6. Apache Kafka и RabbitMQ: семантика и гарантия доставки сообщений
  7. Apache Kafka: основы технологии
  8. Kafka за 20 минут. Ментальная модель и как с ней работать
  9. Семантика exactly-once в Apache Kafka
  10. Особенности семантики exactly-once при разработке для Kafka на Python
  11. Почему доставка exactly-once невозможна и что это вообще такое
  12. Kafka. Лучшие практики применения. Настройки Producer & Consumer
  13. Управление оффсетами в Kafka
  14. Повышаем устойчивость приложений Apache Kafka через обработку исключений
  15. Используете Kafka с микросервисами? Скорее всего, вы неправильно обрабатываете повторные передачи
  16. 7 ошибок при использовании Apache Kafka
  17. Синхронизация асинхронности: Dead Letter и Inbox для обработки зависимых сообщений
  18. работа с Kafka в Go: практическое применение
  19. Как обработать миллион сообщений из kafka и не ждать вечность?!
  20. Под капотом продюсера Kafka: UML-диаграмма публикации сообщений
  21. Работа Apache Kafka на примерах. Поднимаем Kafka Cluster используя docker-compose

Видео

  1. Гарантии доставки на примере Apache Kafka | Никита Ешкеев
  2. Exactly-once Kafka | Артём Кулешов | Golang Meetup 2023 | СберМаркет Tech
  3. Виктор Гамов — Один раз в год сады цветут: разбор семантики «exactly once» Apache Kafka
  4. Что такое гарантии доставки at most once в Kafka?
  5. Apache Kafka: внутреннее устройство, гарантии доставки, особенности, кейсы использования
  6. Алексей Кашин — Надежно отправляем события в Apache Kafka. От CDC до паттерна Transactional Outbox
  7. Надежная отправка событий в Apache Kafka: от CDC до Transactional Outbox — Алексей Кашин, Т-Банк
  8. TRANSACTIONAL OUTBOX | Главный Паттерн Микросервисной Архитектуры
  9. Паттерн Outbox - теория и практика | Архитектура Микросервисов
  10. Паттерны микросервисной архитектуры - Лекция 1 - Transactional Outbox
  11. Гарантия доставки. История одного собеса. Паттерн Transactional outbox (Ксения Погорельских)
  12. Transactional Outbox Pattern | Cockroach University (en)
  13. Kafka и Transactional Outbox. Есть ли альтернативы? / Сергей Попов (Синимекс)
  14. Оптимизация хранения transactional outbox в Postgres — Николай Рудопас, Т-Банк
  15. Idempotence producer
  16. HighLoad++:Паттерны проектирования приложений на Apache Kafka / Александр Сибиряков (Scrapinghub)
  17. HighLoad++:Брокер сообщений Kafka в условиях повышенной нагрузки / Артём Выборнов (Rambler&Co)

Книги

  1. Apache Kafka. Потоковая обработка и анализ данных - Гвен Шапира, Тодд Палино, Раджини Сиварам, Крит Петти
  2. Kafka в действии (2022) - Дилан Скотт, Виктор Гамов и Дейв Клейн
  3. Effective Kafka: A Hands-On Guide to Building Robust and Scalable Event-Driven Applications with Code Examples in Java (2021) - Emil Koutanov(eng)