acks в Kafka: 0, 1 и all

Когда продюсер считает запись успешной и почему acks=1 при replication factor 3 всё равно теряет данные.

Параметр acks отвечает на один вопрос: в какой момент продюсер считает запись успешной.

acks=0 — не ждёт ничего. Отправил и забыл. Потери не будут даже замечены приложением, потому что никакой обратной связи нет. Допустимо только для метрик и телеметрии, где потеря части точек не меняет картину.

acks=1 — ждёт подтверждения от лидера партиции. Выглядит разумным компромиссом и именно поэтому опасен: между записью на лидера и репликацией на фолловеров есть окно. Если лидер умирает внутри этого окна, новый лидер выбирается из ISR с более коротким логом, и всё, что не успело реплицироваться, отрезается при truncate. Продюсер при этом уже получил подтверждение и ничего повторять не будет. Replication factor 3 от этого не спасает.

acks=all — ждёт, пока запись подтвердят все реплики из ISR. С Kafka 3.0 это значение по умолчанию (KIP-679), вместе с включённой по умолчанию идемпотентностью продюсера.

Ключевая тонкость: acks=all означает «все реплики из ISR», а не «все реплики вообще». Если ISR сжался до одного лидера, «все» — это он один, и гарантия исчезает. Поэтому acks=all работает только в связке с min.insync.replicas ≥ 2: тогда при нехватке синхронных реплик брокер отклонит запись вместо того, чтобы принять её в одиночку.

Рабочая формула для прода: replication.factor=3, min.insync.replicas=2, acks=all. Она переживает потерю одной ноды без потери данных и без остановки записи. Цена — при потере двух нод запись останавливается, и это бизнес-решение, которое стоит явно проговорить в требованиях.

Разобрать это в симуляторе Интерактивный сценарий: настраиваешь кластер, ломаешь его и смотришь, что происходит

Частые вопросы

acks=all сильно замедляет запись?

Задержка вырастает на время репликации внутри кластера — обычно единицы миллисекунд. Пропускная способность почти не страдает, потому что записи идут пакетами.

Что такое min.insync.replicas?

Минимальное число синхронных реплик, при котором брокер соглашается принять запись с acks=all. При меньшем числе возвращается ошибка NOT_ENOUGH_REPLICAS.

Нужна ли идемпотентность вместе с acks=all?

Да. acks=all защищает от потерь, идемпотентность — от дублей, которые создаёт сам продюсер при повторной отправке после таймаута.

Дальше по теме

Что такое партиция в Kafka Consumer lag: что это и как с ним работать ISR и min.insync.replicas Ребалансировка consumer group Retry-топик и DLQ в Kafka