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
Материалы
- Введение в Apache Kafka для системных аналитиков и проектировщиков интеграций
- Гарантии доставки сообщений в Kafka
- Синхронная и асинхронная отправка сообщений в Apache Kafka
- Выстрелил и забыл: 3 основные стратегии отправки сообщений в Kafka
- Что такое гарантия доставки сообщений или как избавиться от дублей и потерь в Apache Kafka и других Big Data брокерах
- Apache Kafka и RabbitMQ: семантика и гарантия доставки сообщений
- Apache Kafka: основы технологии
- Kafka за 20 минут. Ментальная модель и как с ней работать
- Семантика exactly-once в Apache Kafka
- Особенности семантики exactly-once при разработке для Kafka на Python
- Почему доставка exactly-once невозможна и что это вообще такое
- Kafka. Лучшие практики применения. Настройки Producer & Consumer
- Управление оффсетами в Kafka
- Повышаем устойчивость приложений Apache Kafka через обработку исключений
- Используете Kafka с микросервисами? Скорее всего, вы неправильно обрабатываете повторные передачи
- 7 ошибок при использовании Apache Kafka
- Синхронизация асинхронности: Dead Letter и Inbox для обработки зависимых сообщений
- работа с Kafka в Go: практическое применение
- Как обработать миллион сообщений из kafka и не ждать вечность?!
- Под капотом продюсера Kafka: UML-диаграмма публикации сообщений
- Работа Apache Kafka на примерах. Поднимаем Kafka Cluster используя docker-compose
Видео
- Гарантии доставки на примере Apache Kafka | Никита Ешкеев
- Exactly-once Kafka | Артём Кулешов | Golang Meetup 2023 | СберМаркет Tech
- Виктор Гамов — Один раз в год сады цветут: разбор семантики «exactly once» Apache Kafka
- Что такое гарантии доставки at most once в Kafka?
- Apache Kafka: внутреннее устройство, гарантии доставки, особенности, кейсы испо льзования
- Алексей Кашин — Надежно отправляем события в Apache Kafka. От CDC до паттерна Transactional Outbox
- Надежная отправка событий в Apache Kafka: от CDC до Transactional Outbox — Алексей Кашин, Т-Банк
- TRANSACTIONAL OUTBOX | Главный Паттерн Микросервисной Архитектуры
- Паттерн Outbox - теория и практика | Архитектура Микросервисов
- Паттерны микросервисной архитектуры - Лекция 1 - Transactional Outbox
- Гарантия доставки. История одного собеса. Паттерн Transactional outbox (Ксения Погорельских)
- Transactional Outbox Pattern | Cockroach University (en)
- Kafka и Transactional Outbox. Есть ли альтернативы? / Сергей Попов (Синимекс)
- Оптимизация хранения transactional outbox в Postgres — Николай Рудопа с, Т-Банк
- Idempotence producer
- HighLoad++:Паттерны проектирования приложений на Apache Kafka / Александр Сибиряков (Scrapinghub)
- HighLoad++:Брокер сообщений Kafka в условиях повышенной нагрузки / Артём Выборнов (Rambler&Co)
Книги
- Apache Kafka. Потоковая обработка и анализ данных - Гвен Шапира, Тодд Палино, Раджини Сиварам, Крит Петти
- Kafka в действии (2022) - Дилан Скотт, Виктор Гамов и Дейв Клейн
- Effective Kafka: A Hands-On Guide to Building Robust and Scalable Event-Driven Applications with Code Examples in Java (2021) - Emil Koutanov(eng)