Що таке топiк (topic) у Kafka
Уявіть телеканали:
🟢 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 топіки
- Request-response патерни — краще HTTP/gRPC
- Гарантована доставка одному одержувачу — краще RabbitMQ
- Дані потрібно часто оновлювати/змінювати — краще БД
🟡 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:
- Фоновий потік
LogCleanerсканує сегменти (поріг:min.cleanable.dirty.ratio=0.5) - Будує hash-таблицю
offset → ключдля всіх записів - Переписує сегменти, залишаючи лише останні значення для кожного ключа
- 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
- Топiк з 0 партицій — неможливо, Kafka вимагає мінімум 1 партицію при створенні
- Зменшення партицій — неможливе без видалення топiка (
alter --partitionsтільки збільшує) - Топiк з RF > кількості брокерів — помилка створення (
Replication factor: 3 larger than available brokers: 2) - Ім’я топiка з крапкою (
.) або підкресленням (_) — у старих версіях призводило до конфліктів з internal topics (__consumer_offsets) - Одночасний запис при ребалансі 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
- Плануйте партиції:
partitions = max(producer_throughput, consumer_throughput) * 1.5 - Використовуйте
min.insync.replicas=2при RF=3 для критичних даних - Розділяйте топіки по бізнес-доменах — спрощує масштабування та моніторинг
- Compact для state, Delete для подій — правильна політика під задачу
- Compression:
lz4для throughput,zstdдля storage економії - Batch tuning:
batch.size=256KB,linger.ms=10для high-throughput продюсерів - Моніторьте Under-Replicated Partitions — перший індикатор проблем кластера
- Використовуйте 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]]