Питання 1 · Розділ 15

Що таке топiк (topic) у Kafka

Уявіть телеканали:

Мовні версії: English Russian Ukrainian

🟢 Junior Level

Що таке топiк?

Топiк (Topic) — це іменований канал (логічна категорія), у який продюсери надсилають повідомлення, а консюмери їх читають. Це основна абстракція для організації даних у Kafka.

Чим топiк відрізняється від черги: у черзі повідомлення прочитано = видалено. У топіку повідомлення зберігається заданий час (retention), і його можуть читати скільки завгодно незалежних груп консюмерів. Це ключова відмінність від традиційних message brokers (RabbitMQ).

Аналогія

Уявіть телеканали:

  • Topic “orders” — канал про замовлення
  • Topic “users” — канал про користувачів
  • Topic “notifications” — канал про сповіщення

Кожен продюсер «мовить» у свій канал, кожен консюмер «налаштовує приймач» на потрібний канал.

Важлива відмінність від телеканалів: у Kafka одне й те саме повідомлення можуть прочитати кілька незалежних груп, кожна зі своєю швидкістю і зі свого місця.

Простий приклад

Продюсер → Topic "orders" → Консюмер
Продюсер → Topic "users"   → Консюмер
// Продюсер надсилає у топік
producer.send(new ProducerRecord<>("orders", "order-data"));

// Консюмер читає з топiка
consumer.subscribe(List.of("orders"));

Основні властивості

  • Топік створюється із зазначенням кількості партицій (під-каналів для паралелізму) та коефіцієнта реплікації (скільки копій зберігати на різних серверах для відмовостійкості).
  • Повідомлення зберігаються певний час (retention period)
  • Топік можна створити, змінити та видалити
kafka-topics.sh --create \
  --topic orders \
  --partitions 3 \
  --replication-factor 3 \
  --bootstrap-server localhost:9092

Коли НЕ використовувати Kafka топіки

  1. Request-response патерни — краще HTTP/gRPC
  2. Гарантована доставка одному одержувачу — краще RabbitMQ
  3. Дані потрібно часто оновлювати/змінювати — краще БД

🟡 Middle Level

Логічна та фізична структура

Логічно: топiк — це категорія для повідомлень.

Фізично: топік складається з партицій, розподілених по брокерах. Кожна партиція — це набір файлів на диску.

Topic "orders"
├── Partition 0 → Broker A
├── Partition 1 → Broker B
└── Partition 2 → Broker C

Cleanup Policies

Дві основні політики очищення:

Policy Опис Use Case
delete (за замовч.) Повідомлення видаляються після закінчення retention Події, логи, замовлення
compact Зберігає лише останнє значення для кожного ключа Профілі користувачів, поточні ціни

Файлова структура партиції

/partition-0/
├── 00000000000000000000.log       # дані
├── 00000000000000000000.index     # індекс за offset
└── 00000000000000000000.timeindex # індекс за часом

Гарантії порядку

  • Всередині партиції: строгий порядок (FIFO)
  • Всередині топiка: немає гарантій (якщо партицій > 1)

Конфігурації топiка

Параметр Опис Приклад
cleanup.policy delete або compact delete
retention.ms час зберігання 604800000 (7 днів)
min.insync.replicas мінімум реплік для запису 2
compression.type тип стиснення lz4, snappy, zstd

Типові помилки

Помилка Наслідок Рішення
Занадто мало партицій Обмежує паралелізм консюмерів Плануйте заздалегідь
Без retention Диск заповниться Встановіть retention.ms
Один топік для всіх даних Складно масштабувати Розділяйте по доменах

🔴 Senior Level

Топiк як розподілений append-only лог

Топiк — це nezмiнний розподілений лог дозапису (Immutable Append-only Log), розділений на партиції для масштабованості та відмовостійкості. На рівні брокера кожен топiк керується через LogManager, який зберігає колекцію Log об’єктів (по одному на партицію).

Log Compaction — глибинний механізм

Як працює Log Cleaner:

  1. Фоновий потік LogCleaner сканує сегменти (поріг: min.cleanable.dirty.ratio=0.5)
  2. Будує hash-таблицю offset → ключ для всіх записів
  3. Переписує сегменти, залишаючи лише останні значення для кожного ключа
  4. Tombstone-записи (value = null) позначають ключі для повного видалення

Продуктивність:

  • log.cleaner.threads=1 (за замовчуванням) — для більшості достатньо
  • log.cleaner.io.buffer.size=512KB — буфер для читання/запису
  • log.cleaner.backoff.ms=15000 — пауза між циклами

Use Cases:

  • Зберігання профілю користувача (Changelog pattern)
  • Поточний стан агрегату (Event Sourcing)
  • Відновлення state у Kafka Streams (changelog topics)

Сегментна архітектура

Активний сегмент → запис (sealed при досягненні segment.bytes або segment.ms)
Закриті сегменти → тільки читання, кандидати на видалення/compaction

segment.bytes=1GB
segment.ms=7 днів
segment.index.bytes=10MB

Переваги сегментації:

  • O(1) видалення — видаляються цілі сегменти
  • Ефективна робота з OS Page Cache
  • Паралельне очищення (різні потоки чистять різні сегменти)
  • Індексна навігація — бінарний пошук за .index файлами

Конфігурації рівня Senior

Параметр Вплив Рекомендація
min.insync.replicas Критично для durability (у зв’язці з acks=all) 2 при RF=3
unclean.leader.election.enable Availability (true) vs Durability (false) false для критичних даних
message.format.version Невідповідність → overhead конвертації Єдина версія у кластері
max.message.bytes Ліміт розміру повідомлення 1048588 (1MB за замовч.)

Edge Cases

  1. Топiк з 0 партицій — неможливо, Kafka вимагає мінімум 1 партицію при створенні
  2. Зменшення партицій — неможливе без видалення топiка (alter --partitions тільки збільшує)
  3. Топiк з RF > кількості брокерів — помилка створення (Replication factor: 3 larger than available brokers: 2)
  4. Ім’я топiка з крапкою (.) або підкресленням (_) — у старих версіях призводило до конфліктів з internal topics (__consumer_offsets)
  5. Одночасний запис при ребалансі ISR — можлива втрата повідомлень якщо acks=1 і лідер впав до реплікації

Performance Numbers

Метрика Значення Умови
Throughput на топік ~500 MB/s 12 партицій, lz4, batch.size=256KB
Latency (p99) 5-15 ms acks=all, RF=3, локальний дата-центр
Max partitions/broker ~200 000 Залежить від OS file descriptors
Optimal partitions/broker 2 000-4 000 Для стабільної роботи контролера

Production War Story

Ситуація: Фінтех-компанія використовувала один топік events для всіх типів подій (замовлення, платежі, логіни). Топiк мав 6 партицій. При зростанні навантаження до 50K msg/s консюмери не справлялися — lag зріс експоненційно.

Проблема: При спробі збільшити партиції до 60, ключі замовлень перестали потрапляти в ті ж партиції — порушився порядок обробки платежів. Клієнти побачили дублікати списань.

Рішення: Розділили на 4 доменних топiка (orders, payments, auth, audit), кожен з 20 партиціями. Мігрували через dual-write з періодом «тіні» 48 годин. Додали min.insync.replicas=2 та acks=all для платіжного топiка.

Урок: Розділяйте топіки по бізнес-доменах з самого початку. Плануйте партиції з 10-кратним запасом.

Моніторинг (JMX метрики)

kafka.server:name=BytesInPerSec,type=BrokerTopicMetrics
kafka.server:name=BytesOutPerSec,type=BrokerTopicMetrics
kafka.server:name=MessagesInPerSec,type=BrokerTopicMetrics
kafka.cluster:type=Partition,name=UnderReplicated
kafka.log:type=Log,name=LogEndOffset
kafka.log:type=Log,name=LogStartOffset

Burrow (LinkedIn):

  • Оцінює consumer lag і статус (OK, WARN, ERR)
  • HTTP API для інтеграції з Alertmanager/PagerDuty
  • Не потребує модифікації консюмерів

Highload Best Practices

  1. Плануйте партиції: partitions = max(producer_throughput, consumer_throughput) * 1.5
  2. Використовуйте min.insync.replicas=2 при RF=3 для критичних даних
  3. Розділяйте топіки по бізнес-доменах — спрощує масштабування та моніторинг
  4. Compact для state, Delete для подій — правильна політика під задачу
  5. Compression: lz4 для throughput, zstd для storage економії
  6. Batch tuning: batch.size=256KB, linger.ms=10 для high-throughput продюсерів
  7. Моніторьте Under-Replicated Partitions — перший індикатор проблем кластера
  8. Використовуйте KRaft (Kafka Raft, production-ready з Kafka 3.3+) замість ZooKeeper для нових кластерів. У Kafka 2.x KRaft — experimental.

🎯 Шпаргалка для співбесіди

Обов’язково знати:

  • Топік — логічна категорія для повідомлень, фізично складається з партицій
  • На відміну від черги, повідомлення не видаляються після прочитання — зберігаються заданий час (retention)
  • Cleanup policies: delete (за часом) та compact (останнє значення за ключем)
  • Порядок гарантований тільки всередині партиції, не всередині топiка
  • Топiк — це immutable append-only лог, розділений на партиції
  • min.insync.replicas=2 при RF=3 критично для durability
  • Зменшення партицій неможливе — тільки перестворення топiка
  • Розділяйте топіки по бізнес-доменах з самого початку

Часті уточнюючі запитання:

  • Чи можна зменшити кількість партицій? — Ні, тільки збільшити. Зменшення — через перестворення топiка.
  • Що таке log compaction? — Зберігає лише останнє значення для кожного ключа, видаляє старі.
  • Що станеться якщо топік з 0 партицій? — Неможливо, Kafka вимагає мінімум 1 партицію.
  • Як забезпечити глобальний порядок? — Тільки 1 партиція, але це вбиває паралелізм.

Червоні прапорці (НЕ говорити):

  • «Топiк — це черга, повідомлення видаляються після прочитання» — це не черга
  • «Порядок гарантований у всьому топіку» — тільки всередині партиції
  • «Можна зменшити партиції через alter» — не можна
  • «Один топік на всі події — це нормально» — антипатерн

Пов’язані теми:

  • [[2. Що таке партиція (partition) і навіщо вона потрібна]]
  • [[3. Як дані розподіляються по партиціях]]
  • [[27. Що таке retention policy]]
  • [[28. Як видаляються старі повідомлення з топiка]]
  • [[16. Що таке реплікація у Kafka]]