Що таке реплікація в 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% гарантії збереження даних у продакшені три налаштування повинні працювати суворо разом:
replication.factor = 3(на рівні топіка) — 3 копії даних на різних фізичних серверах.min.insync.replicas = 2(на рівні топіка або брокера) — мінімальна кількість реплік в ISR, що підтвердили запис.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)
- Log End Offset (LEO): зсув наступного повідомлення, яке буде записано в лог конкретної репліки. У лідера та фолловерів свої локальні LEO.
- High Watermark (HW): максимальний зсув, який успішно скопійовано на всі репліки з поточного ISR.
- Правило консьюмера: звичайні консьюмери мають право читати дані лише до High Watermark! Непідтверджені репліками дані клієнтам не віддаються.
- 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 був у нормі. Лідер встиг успішно записати повідомлення у свій локальний сегмент лога на диск. Проте під час очікування підтверджень від фолловерів вони відвалилися за таймаутом, і розмір ISR зменшився нижче допустимого порогу.- Для продюсера обидва винятки є сигналом для повторної спроби (retry), але при ввімкненій ідемпотентності дублікати у лідера будуть відфільтровані за 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.