Что такое топик (topic) в Kafka
Представьте телеканалы:
🟢 Junior Level
Что такое топик?
Топик (Topic) — это именованный канал (логическая категория), в который продюсеры отправляют сообщения, а консьюмеры их читают. Это основная абстракция для организации данных в Kafka.
Чем топик отличается от очереди: в очереди сообщение прочитано = удалено. В топике сообщение сохраняется заданное время (retention), и его могут читать сколько угодно независимых групп консьюмеров. Это ключевое отличие от традиционных message brokers (RabbitMQ).
Аналогия
Представьте телеканалы:
- Topic “orders” — канал о заказа
- Topic “users” — канал о пользователях
- Topic “notifications” — канал об уведомлениях
Каждый продюсер «вещает» в свой канал, каждый консьюмер «настраивает приёмник» на нужный канал.
Важное отличие от телеканалов: в Kafka одно и то же сообщение могут прочитать несколько независимых групп, каждая со своей скоростью и со своего места.
Простой пример
Продюсер → Topic "orders" → Консьюмер
Продюсер → Topic "users" → Консьюмер
// Продюсер отправляет в топик
producer.send(new ProducerRecord<>("orders", "order-data"));
// Консьюмер читает из топика
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
Логическая и физическая структура
Логически: топик — это категория для сообщений.
Физически: топик состоит из партиций, распределённых по брокерам. Каждая партиция — это набор файлов на диске.
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)
- Внутри топика: нет гарантий (если партиций > 1)
Конфигурации топика
| Параметр | Описание | Пример |
|---|---|---|
cleanup.policy |
delete или compact | delete |
retention.ms |
время хранения | 604800000 (7 дней) |
min.insync.replicas |
минимум реплик для записи | 2 |
compression.type |
тип сжатия | lz4, snappy, zstd |
Типичные ошибки
| Ошибка | Последствие | Решение |
|---|---|---|
| Слишком мало партиций | Ограничивает параллелизм консьюмеров | Планируйте заранее |
| Без retention | Диск заполнится | Установите retention.ms |
| Один топик для всех данных | Сложно масштабировать | Разделяйте по доменам |
🔴 Senior Level
Топик как распределённый append-only лог
Топик — это неизменяемый распределённый лог дозаписи (Immutable Append-only Log), разделённый на партиции для масштабируемости и отказоустойчивости. На уровне брокера каждый топик управляется через 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 |
Несоответствие → оверхед конвертации | Единая версия в кластере |
max.message.bytes |
Лимит размера сообщения | 1048588 (1MB по умолчанию) |
Edge Cases
- Топик с 0 партиций — невозможен, Kafka требует минимум 1 партицию при создании
- Уменьшение партиций — невозможно без удаления топика (
alter --partitionsтолько увеличивает) - Топик с RF > количества брокеров — ошибка создания (
Replication factor: 3 larger than available brokers: 2) - Имя топика с точкой (
.) или подчёркиванием (_) — в старых версиях приводило к конфликтам с 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для всех типов событий (заказы, платежи, логины). Топик имел 6 партиций. При росте нагрузки до 50K msg/s консьюмеры не справлялись — lag рос экспоненциально.Проблема: При попытке увеличить партиции до 60, ключи заказов перестали попадать в те же партиции — нарушился порядок обработки платежей. Клиенты увидели дубликаты списаний.
Решение: Разделили на 4 доменных топика (
orders,payments,auth,audit), каждый с 20 партициями. Мигрировали через dual-write с периодом «тени» 48 часов. Добавилиmin.insync.replicas=2иacks=allдля платежного топика.Урок: Разделяйте топики по бизнес-доменам с самого начала. Планируйте партиции с 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(последнее значение по ключу) - Порядок гарантирован только внутри партиции, не внутри топика
- Топик — это immutable append-only лог, разделённый на партиции
min.insync.replicas=2при RF=3 критично для durability- Уменьшение партиций невозможно — только пересоздание топика
- Разделяйте топики по бизнес-доменам с самого начала
Частые уточняющие вопросы:
- Можно ли уменьшить количество партиций? — Нет, только увеличить. Уменьшение — через пересоздание топика.
- Что такое log compaction? — Хранит только последнее значение для каждого ключа, удаляет старые.
- Что произойдёт если топик с 0 партиций? — Невозможно, Kafka требует минимум 1 партицию.
- Как обеспечить глобальный порядок? — Только 1 партиция, но это убивает параллелизм.
Красные флаги (НЕ говорить):
- «Топик — это очередь, сообщения удаляются после прочтения» — это не очередь
- «Порядок гарантирован во всём топике» — только внутри партиции
- «Можно уменьшить партиции через alter» — нельзя
- «Один топик на все события — это нормально» — антипаттерн
Связанные темы:
- [[2. Что такое партиция (partition) и зачем она нужна]]
- [[3. Как данные распределяются по партициям]]
- [[27. Что такое retention policy]]
- [[28. Как удаляются старые сообщения из топика]]
- [[16. Что такое репликация в Kafka]]