📨 Раздел 15 · Вопрос #16

Что такое репликация в Kafka

Количество копий задается параметром Replication Factor (RF) на уровне топика:


🟢 Junior Level

30-секундный ответ

Репликация в Kafka — это механизм копирования данных партиций на несколько независимых брокеров кластера для обеспечения высокой доступности (High Availability) и отказоустойчивости (Fault Tolerance).

Количество копий задается параметром Replication Factor (RF) на уровне топика:

  • Leader (Лидер): ровно одна реплика партиции назначается лидером. Она принимает все входящие операции записи от продюсеров и (по умолчанию) обслуживает чтение консьюмерами.
  • Followers (Последователи): остальные реплики пассивно вычитывают новые сообщения у лидера через внутренние Fetch-запросы, полностью дублируя его commit log на своих дисках.
  • Если брокер с лидером выходит из строя, кластер автоматически выбирает нового лидера из числа актуальных фолловеров без остановки сервиса.

Наглядная аналогия из жизни

Представьте главного нотариуса и его помощников в разных зданиях:

  • Лидер: главный нотариус, который лично заверяет все новые договоры (записи) в оригинале гроссбуха.
  • Фолловеры: помощники в соседних офисах, которые непрерывно запрашивают у главного копии новых страниц и вклеивают их в свои дубликаты гроссбуха.
  • Если здание главного нотариуса обесточено, один из помощников с самым полным журналом объявляется новым главным нотариусом.

Создание топика с репликацией

# Создание топика orders с 3 партициями и 3 репликами на кластере
kafka-topics.sh --bootstrap-server localhost:9092 --create \
  --topic orders \
  --partitions 3 \
  --replication-factor 3 \
  --config min.insync.replicas=2

🟡 Middle Level

Механика работы ISR (In-Sync Replicas)

Брокер-лидер отслеживает актуальность фолловеров с помощью списка ISR (In-Sync Replicas):

  • Фолловер считается синхронизированным («in-sync»), если он регулярно отправляет FetchRequest к лидеру и отставание по времени не превышает replica.lag.time.max.ms (по умолчанию 30 секунд).
  • Если фолловер завис (GC-пауза, сетевой сбой, диск I/O), лидер исключает его из ISR.
  • Как только фолловер догоняет лидера, он автоматически возвращается в ISR.
Кластер с Replication Factor = 3:

[ Broker 1 (Leader) ] ───(Fetch)───► [ Broker 2 (Follower) ]  -> Входит в ISR ✅
        │
        └────────────────(Fetch)───► [ Broker 3 (Follower) ]  -> Lag > 30s -> Исключен из ISR ❌

Текущий ISR: [Broker 1, Broker 2]

Золотой треугольник надежности Kafka

Для 100% гарантии сохранности данных в продакшене три настройки должны работать строго вместе:

  1. replication.factor = 3 (на уровне топика) — 3 копии данных на разных физических серверах.
  2. min.insync.replicas = 2 (на уровне топика или брокера) — минимальное число реплик в ISR, подтвердивших запись.
  3. acks = all (или -1) (на уровне продюсера) — продюсер ждет подтверждения от всех участников текущего ISR.
Properties producerProps = new Properties();
producerProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "broker1:9092,broker2:9092");
// Продюсер требует подтверждения от всего кворума ISR
producerProps.put(ProducerConfig.ACKS_CONFIG, "all");
// Включение идемпотентности гарантирует отсутствие дублей при ретраях репликации
producerProps.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, "true");

🔴 Senior Level

Внутренние маркеры репликации: LEO, HW и Leader Epoch

Репликация оперирует тремя фундаментальными смещениями:

  0     1     2     3     4     5     6     7     8
┌───┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│ m0│ m1  │ m2  │ m3  │ m4  │ m5  │ m6  │ m7  │     │
└───┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
                            ▲                 ▲
                            │                 │
                      High Watermark (HW)   Log End Offset (LEO)
  1. Log End Offset (LEO): смещение следующего сообщения, которое будет записано в лог конкретной реплики. У лидера и фолловеров свои локальные LEO.
  2. High Watermark (HW): максимальное смещение, которое успешно скопировано на все реплики из текущего ISR.
    • Правило консьюмера: обычные консьюмеры имеют право читать данные только до High Watermark! Неподтвержденные репликами данные клиентам не отдаются.
  3. Leader Epoch (KIP-101): монотонно растущее число эпохи лидера, предотвращающее расхождение логов (Log Divergence) и фантомную потерю данных при каскадных сбоях лидеров.

Чтение с ближайшей реплики (Rack Awareness / KIP-392)

Исторически консьюмеры читали только с лидера. В мультизональных облаках (AWS Multi-AZ, GCP) это приводило к огромным расходам на межзональный трафик (Cross-AZ traffic). Начиная с Kafka 2.4 (KIP-392), консьюмер может читать напрямую с Follower-реплики, если они находятся в одном дата-центре:

# На брокере:
broker.rack=eu-west-1a

# На консьюмере:
client.rack=eu-west-1a
# Топик должен разрешать чтение с фолловеров
  • Фолловер отдает консьюмеру данные только до своего локального High Watermark.

4 Tricky Questions

1. Почему связка replication.factor = 3 и acks = all абсолютно бесполезна для защиты от потери данных, если min.insync.replicas = 1?

Ответ:

  • Продюсер с acks = all ждет подтверждения от всех реплик, находящихся в текущем ISR.
  • Если два брокера-фолловера упали или отстали из-за сети, брокер-лидер исключит их из ISR. В ISR останется ровно один участник — сам лидер (ISR = [Broker 1]).
  • Так как min.insync.replicas = 1, лидер посчитает, что условие минимального кворума выполнено, запишет сообщение локально и успешно ответит продюсеру: «Запись подтверждена!».
  • Если в следующую секунду у лидера сгорит жесткий диск, данные будут безвозвратно утеряны, несмотря на флаг acks = all.
  • Вывод: Только при min.insync.replicas = 2 брокер отклонит запись ошибкой NotEnoughReplicasException, уведомив продюсера о невозможности гарантировать надежность.

2. Как внедрение Leader Epoch (KIP-101) решило проблему усечения логов (Log Truncation) и потери данных, возникавшую при использовании старого механизма High Watermark?

Ответ:

  • В старых версиях Kafka фолловер обновлял свой High Watermark только со следующим Fetch-ответом от лидера.
  • Если фолловер $F$ записал сообщение, но упал до обновления локального HW, то после перезагрузки он автоматически усекал свой лог до старого HW (считая несогласованные сообщения «мусором»).
  • Если перед этим упал и лидер $L$, и брокер $F$ становился новым лидером, законно подтвержденные продюсеру сообщения навсегда исчезали из кластера.
  • Leader Epoch ввел версионирование: при рестарте фолловер обращается к новому лидеру с запросом LeaderEpochRequest («Каков твой конец эпохи $N$?»), сравнивает фактические смещения эпох и обрезает лог только в том случае, если данные реально разошлись, предотвращая случайное удаление валидных записей.

3. Чем отличается исключение NotEnoughReplicasException от NotEnoughReplicasAfterAppendException?

Ответ:

  • NotEnoughReplicasException: Лидер проверил размер ISR до добавления сообщения в свой локальный лог. Видя, что размер ISR меньше min.insync.replicas, он мгновенно отвергает запрос продюсера. Лог лидера остается чистым.
  • NotEnoughReplicasAfterAppendException: В момент прихода запроса ISR был в порядке. Лидер успел успешно записать сообщение в свой локальный log segment на диск. Но в процессе ожидания подтверждений от фолловеров фолловеры отвалились по таймауту, и ISR уменьшился ниже допустимого предела.
  • Для продюсера оба исключения являются поводом для ретрая, но при включенной идемпотентности дубликаты у лидера будут отфильтрованы по sequence number.

4. Что такое unclean.leader.election.enable и почему эта настройка по умолчанию строго false в современных версиях Kafka?

Ответ:

  • Если лидер партиции падает, а все остальные реплики в данный момент не входят в ISR (отстали по времени или были недоступны):
    • При unclean.leader.election.enable = false: партиция становится полностью недоступной для чтения и записи. Кластер ждет оживления лидера или кого-то из ISR. Доступность (Availability) приносится в жертву целостности (Consistency).
    • При unclean.leader.election.enable = true: брокер выбирает лидером несинхронизированную реплику (Out-of-Sync follower).
  • Опасность: несинхронизированный фолловер не содержит последних сотен или тысяч записей. Все эти записи безвозвратно теряются для консьюмеров, а оффсеты перезаписываются новыми данными, порождая повреждение данных во всей системе.

🎯 Шпаргалка для интервью

Главное о репликации

  • Зачем нужна: отказоустойчивость и непрерывность бизнеса при падении серверов.
  • Роли: ровно один Leader (read/write) и $N-1$ Followers (пассивные репликаторы лога).
  • ISR (In-Sync Replicas): множество реплик, отставание которых от лидера не превышает replica.lag.time.max.ms.
  • Продакшн-формула: RF = 3, min.insync.replicas = 2, acks = all.
  • High Watermark (HW): граница, до которой данные видны консьюмерам.

Сравнительная таблица состояний репликации

| Сценарий | Доступность на запись | Доступность на чтение | Риск потери данных | | :— | :— | :— | :— | | ISR = 3, min.insync = 2 | ✅ Полная | ✅ Полная | ❌ Нулевой | | ISR = 2, min.insync = 2 | ✅ Полная | ✅ Полная | ❌ Нулевой | | ISR = 1, min.insync = 2 | ❌ Ошибка NotEnoughReplicas | ✅ Полная (по HW) | ❌ Нулевой | | ISR = 1, min.insync = 1 | ✅ Полная | ✅ Полная | ⚠️ Критический риск при падении лидера |

Красные флаги на собеседовании (Чего говорить нельзя)

  • ❌ «Каждая реплика партиции принимает параллельные записи от разных продюсеров» — только Лидер принимает запись!
  • ❌ «Если поставить acks=all, данные никогда не потеряются даже при min.insync.replicas=1» — грубое непонимание работы ISR.
  • ❌ «Консьюмер вычитывает самые свежие данные сразу, как только лидер положил их в память» — консьюмеры видят данные строго до High Watermark.

Связанные вопросы