Learning Platform
Глоссарий Troubleshooting
Урок 03.03 · 20 мин
Продвинутый
acksmin.insync.replicasRetriesdelivery.timeout.msIdempotence

Acks и Retries

Настройка acks — это компромисс между надёжностью и производительностью. Этот урок объясняет, что на самом деле означают acks=0, acks=1 и acks=all, как min.insync.replicas влияет на реальную гарантию, и что происходит при ошибках сети — механизм retry.

Понимание этих параметров критически важно: неправильная конфигурация может означать, что ваш продюсер думает, что данные сохранены, хотя они потеряны.


acks=0 — Fire and Forget

При acks=0 продюсер не ждёт никакого подтверждения от брокера. Сообщение считается успешно отправленным, как только оно покинуло буфер продюсера и было передано в сеть.

producer = KafkaProducer(
    bootstrap_servers=['broker:9092'],
    acks=0,  # Fire and forget
)

future = producer.send('metrics', value={'cpu': 95.2})
# future.get() всегда вернёт offset=0 или фиктивный offset
# Нет гарантии, что брокер получил сообщение

Характеристики:

  • Максимальная пропускная способность (нет round-trip ожидания)
  • Минимальная latency отправки
  • Нет гарантии доставки: брокер может упасть до записи, сеть — обрезать соединение
  • retries игнорируется — продюсер не знает об ошибках брокера

Применение: метрики и аналитические события, где потеря 0.1% данных допустима и throughput критически важен.


acks=1 — Leader Acknowledged

При acks=1 продюсер ждёт подтверждения от leader-реплики партиции. Брокер записывает сообщение в свой log и отвечает продюсеру.

producer = KafkaProducer(
    bootstrap_servers=['broker:9092'],
    acks='1',  # или acks=1 — эквивалентно
)

Характеристики:

  • Leader подтвердил запись — сообщение в log leader’а
  • Follower-реплики могут ещё не получить сообщение
  • Если leader падает до репликации на follower — сообщение потеряно
acks=1: риск потери при падении leader

Producer → ProduceRequest

Продюсер отправляет запись на broker-leader партиции. ProduceRequest содержит один или несколько батчей.

Leader: записал, ответил ACK

Broker Leader получает запись, пишет в свой log (append). Отвечает ProduceResponse с offset — всё в порядке с точки зрения продюсера.
реплицирует...

Follower: ещё не получил

Follower-реплики асинхронно тянут (fetch) данные от leader. В момент ACK продюсеру follower может ещё не получить запись. Если leader упадёт в этот момент — запись потеряна: новый leader (бывший follower) не знает об этой записи.

Продюсер: доставка подтверждена (но follower не синхронизирован!)

Продюсер считает доставку успешной (получил ACK). Но если leader упадёт прямо сейчас — новый leader, избранный из follower, не будет содержать эту запись. Данные потеряны, хотя продюсер не знает об этом.

Применение: большинство production-сценариев с умеренными требованиями к надёжности. Риск потери данных существует, но мал (только при одновременном падении leader сразу после записи).


acks=all — All ISR Acknowledged

При acks=all (или acks=-1) продюсер ждёт подтверждения от всех реплик в ISR (In-Sync Replicas — реплики, синхронизированные с leader’ом).

producer = KafkaProducer(
    bootstrap_servers=['broker:9092'],
    acks='all',  # или acks=-1 — эквивалентно
)

Механизм:

  1. Продюсер отправляет запись leader’у
  2. Leader записывает в свой log
  3. Leader ожидает, пока все follower’ы из ISR не подтвердят репликацию (fetch + запись)
  4. Leader отвечает продюсеру ACK

Если leader падает после ACK, новый leader гарантированно содержит запись — она была реплицирована на все ISR-реплики.


min.insync.replicas — критически важный параметр

min.insync.replicas определяет минимальное количество реплик в ISR, которые должны подтвердить запись при acks=all. Устанавливается на уровне топика или брокера.

# На уровне топика (kafka-configs или при создании)
kafka-topics.sh --create --topic orders \
  --replication-factor 3 \
  --config min.insync.replicas=2
WARNING

acks=all с min.insync.replicas=1 ЭКВИВАЛЕНТНО acks=1 с точки зрения надёжности! Если ISR содержит только одну реплику (leader), acks=all ждёт только подтверждения от неё. Падение leader приведёт к потере данных так же, как и при acks=1. Для реальной защиты от потери данных нужны: acks=all + min.insync.replicas=2 + replication.factor=3.

Правильная конфигурация для гарантии без потерь

# Продюсер
producer = KafkaProducer(
    bootstrap_servers=['broker:9092'],
    acks='all',
    retries=10,
    enable_idempotence=True,  # Обязателен при retries > 0 с acks=all
)
# Топик с replication.factor=3, min.insync.replicas=2
# Терпит падение 1 из 3 брокеров без потери данных
# При падении 2 из 3 — запись заблокируется (NotEnoughReplicasException)

Сравнение конфигураций надёжности

КонфигурацияДопустимых паденийПотеря данныхThroughput
acks=0ЛюбоеВозможна всегдаМаксимальный
acks=1До падения leaderПри падении leader до репликацииВысокий
acks=all, min.isr=1До падения leaderПри падении leaderВысокий
acks=all, min.isr=2, RF=31 из 3 брокеровНет (при RF=3)Умеренный
acks=all, min.isr=3, RF=30НетНизкий

Retry-механизм

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

producer = KafkaProducer(
    bootstrap_servers=['broker:9092'],
    acks='all',
    retries=2147483647,          # Максимальное число попыток (по умолчанию в Kafka 2.1+)
    retry_backoff_ms=100,        # Пауза между попытками (по умолчанию 100 мс)
    delivery_timeout_ms=120000,  # Общий таймаут доставки — 2 минуты
    request_timeout_ms=30000,    # Таймаут одного запроса — 30 секунд
)

delivery.timeout.ms — главный контролирующий параметр

delivery.timeout.ms (по умолчанию 120 000 мс = 2 минуты) — это суммарное время, в течение которого продюсер будет пытаться доставить сообщение, включая:

  • время в буфере (до первой отправки)
  • время всех retry-попыток
  • задержки между попытками (retry.backoff.ms)
Жизнь сообщения:
  send() → [буфер] → попытка 1 → FAIL → [пауза 100мс] →
  попытка 2 → FAIL → [пауза 200мс] → попытка 3 → OK
  <─────────────── delivery.timeout.ms ────────────────>

Если delivery.timeout.ms истёк — future.get() выбрасывает TimeoutException.


Ошибки: retriable vs non-retriable

Не все ошибки брокера подлежат повтору.

Retriable ошибки (продюсер повторяет автоматически):

  • LEADER_NOT_AVAILABLE — leader партиции недоступен (переизбрание)
  • NOT_ENOUGH_REPLICAS — ISR меньше min.insync.replicas
  • REQUEST_TIMED_OUT — таймаут запроса
  • NETWORK_EXCEPTION — сетевые ошибки

Non-retriable ошибки (продюсер НЕ повторяет):

  • INVALID_TOPIC_EXCEPTION — топик не существует и auto.create отключён
  • MESSAGE_TOO_LARGE — сообщение превышает max.message.bytes
  • AUTHORIZATION_FAILED — нет прав на топик
  • RECORD_LIST_TOO_LARGE — батч превышает лимит
from kafka.errors import KafkaError

def on_send_error(exc):
    if exc.retriable:
        print(f"Retriable error, будет retry: {exc}")
    else:
        print(f"Fatal error, retry не поможет: {exc}")
        # Нужна ручная обработка, алерт, dead-letter queue

producer.send('orders', value=order) \
    .add_errback(on_send_error)

Риск нарушения порядка при retry

При retries > 0 и max.in.flight.requests.per.connection > 1 возможна ситуация, когда сообщения приходят на брокер в другом порядке:

Продюсер отправляет: Батч 1, Батч 2
Батч 1 потерян → retry
Батч 2 доставлен успешно
Батч 1 доставлен (retry) → порядок нарушен!

Решения:

  1. max.in.flight.requests.per.connection=1 — только один запрос в полёте (снижает throughput)
  2. enable.idempotence=True — брокер сам выстраивает порядок по sequence number (рекомендуется)
TIP

В Kafka 3.0+ enable.idempotence=True является значением по умолчанию. При этом acks автоматически устанавливается в all, retries — в максимальное значение, max.in.flight.requests.per.connection — в 5. Идемпотентность и порядок гарантированы без ручной настройки.


Ключевые выводы

  1. acks=0 — максимальная скорость, нет гарантий. acks=1 — лидер подтвердил. acks=all — все ISR подтвердили.
  2. acks=all без min.insync.replicas=2+ложная безопасность. Эквивалентен acks=1 при ISR=1.
  3. Правильный рецепт надёжности: acks=all + min.insync.replicas=2 + replication.factor=3.
  4. delivery.timeout.ms контролирует суммарное время попыток доставки.
  5. Retry при max.in.flight > 1 может нарушить порядок — используйте enable.idempotence=True.
Проверка знанийKnowledge check
Топик orders: replication.factor=3, min.insync.replicas=2. Продюсер: acks=all. Два из трёх брокеров упали. Что произойдёт при отправке сообщения?
ОтветAnswer
Продюсер получит ошибку NOT_ENOUGH_REPLICAS (или NOT_ENOUGH_REPLICAS_AFTER_APPEND). ISR теперь содержит только 1 реплику (оставшийся брокер), что меньше min.insync.replicas=2. Брокер отклонит запись с retriable ошибкой. Продюсер будет повторять попытки до delivery.timeout.ms. Запись не будет принята, пока хотя бы ещё один брокер не вернётся в ISR. Это корректное поведение: система выбирает доступность только при наличии достаточного числа живых реплик для гарантии сохранности данных.

Проверьте понимание

Результат: 0 из 0
Прикладной
Вопрос 1 из 4. Топик настроен: replication.factor=3, min.insync.replicas=2. Продюсер: acks=all. Один follower отстаёт и выпадает из ISR (ISR теперь содержит leader + 1 follower = 2 реплики). Что произойдёт при следующей записи продюсера?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 6