Вопрос 1 · Раздел 15

Что такое топик (topic) в Kafka

Представьте телеканалы:

Версии по языкам: English Russian Ukrainian

🟢 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 топики

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

🟡 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:

  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 Несоответствие → оверхед конвертации Единая версия в кластере
max.message.bytes Лимит размера сообщения 1048588 (1MB по умолчанию)

Edge Cases

  1. Топик с 0 партиций — невозможен, Kafka требует минимум 1 партицию при создании
  2. Уменьшение партиций — невозможно без удаления топика (alter --partitions только увеличивает)
  3. Топик с RF > количества брокеров — ошибка создания (Replication factor: 3 larger than available brokers: 2)
  4. Имя топика с точкой (.) или подчёркиванием (_) — в старых версиях приводило к конфликтам с 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 для всех типов событий (заказы, платежи, логины). Топик имел 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

  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 (последнее значение по ключу)
  • Порядок гарантирован только внутри партиции, не внутри топика
  • Топик — это 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]]