Apache Kafka это распределённый журнал (лог) сообщений: продюсеры дописывают события в конец, консьюмеры читают с нужной позиции. В отличие от классической очереди, прочитанное сообщение не удаляется: его могут прочитать другие потребители, его можно перечитать заново. На этом держатся стриминг, CDC и интеграция микросервисов.
Топики и партиции
Топик это именованный поток сообщений, разбитый на партиции. Партиция это упорядоченный лог только на дописывание; у каждого сообщения в партиции есть номер, оффсет.
- Порядок гарантирован только внутри партиции, не по всему топику.
- Партиции дают параллелизм: разные партиции живут на разных брокерах и читаются разными консьюмерами.
- Сообщение имеет ключ, значение, заголовки и время.
Ключ определяет партицию: продюсер считает хеш ключа и берёт остаток от деления на число партиций. Все события одного ключа (например, order_id) попадают в одну партицию и читаются по порядку. Без ключа сообщения распределяются по партициям для равномерности.
Подводные камни:
- Горячий ключ: если один ключ даёт 30% трафика, его партиция перегружена, а параллелизм не помогает.
- Увеличение числа партиций меняет отображение ключей на партиции: новые события ключа пойдут в другую партицию, порядок между старыми и новыми не гарантирован. Число партиций закладывают с запасом.
Хранение
Сообщения хранятся по политике retention: по времени (например, 7 дней) или размеру, независимо от того, прочитаны ли они. Альтернатива для топиков-состояний: log compaction, когда Kafka хранит хотя бы последнее значение каждого ключа. Компактированный топик удобен как «таблица текущих состояний» (последний профиль пользователя).
Consumer groups
Консьюмеры с одинаковым group.id образуют группу и делят партиции топика: каждая партиция в каждый момент читается одним консьюмером группы.
- Консьюмеров больше, чем партиций: лишние простаивают. Число партиций это потолок параллелизма группы.
- Разные группы читают топик независимо: аналитика и сервис уведомлений получают все сообщения каждый.
- При добавлении, падении или долгом молчании консьюмера происходит ребалансировка: партиции перераспределяются.
Оффсеты и lag
Консьюмер сам сообщает, до какого места он обработал партицию: коммит оффсета (хранится во внутреннем топике __consumer_offsets). После рестарта чтение продолжается с закоммиченного оффсета.
- Коммит после обработки: при падении между обработкой и коммитом сообщение обработается повторно. Это at-least-once.
- Коммит до обработки: при падении сообщение потеряется. Это at-most-once.
Consumer lag = последний оффсет в партиции (log end offset) минус закоммиченный оффсет группы. Это главная метрика здоровья консьюмера: растущий lag значит, что консьюмер не успевает.
Репликация и надёжность записи
У каждой партиции есть лидер и реплики на других брокерах (replication.factor, обычно 3). ISR (in-sync replicas) это реплики, не отставшие от лидера.
Настройка продюсера acks:
acks=0: не ждать подтверждения. Быстро, возможны потери.acks=1: ждать записи на лидере. Потеря при падении лидера до репликации.acks=all: ждать записи на всех репликах из ISR. В связке сmin.insync.replicas=2при факторе 3 запись подтверждается минимум двумя репликами.
Идемпотентный продюсер (enable.idempotence, в современных версиях включён по умолчанию) нумерует сообщения, и брокер отбрасывает дубли от ретраев продюсера в пределах партиции.
Транзакции позволяют атомарно записать в несколько партиций и закоммитить оффсеты чтения: паттерн read-process-write внутри Kafka с exactly-once. Консьюмеры с isolation.level=read_committed не видят сообщений незавершённых транзакций. Важно: exactly-once работает внутри Kafka; запись во внешнюю базу требует идемпотентного приёмника.
Экосистема
- KRaft: Kafka хранит метаданные кластера сама, без ZooKeeper. В Kafka 4.0 поддержку ZooKeeper убрали.
- Schema Registry: схемы сообщений (Avro, Protobuf, JSON Schema) и правила совместимости при их изменении.
- Kafka Connect: готовые коннекторы источников и приёмников (Debezium для CDC, S3, JDBC).
Частые ошибки
- Ожидать глобального порядка по топику.
- Делать консьюмеров больше, чем партиций, и ждать роста скорости.
- Коммитить оффсет до обработки и терять сообщения.
- Долгая обработка без учёта
max.poll.interval.ms: консьюмера выкидывают из группы, начинается бесконечная ребалансировка. - Менять число партиций у топика с ключами, не думая о порядке.
Что спросят на собесе
- Топик, партиция, оффсет; где гарантирован порядок.
- Как ключ влияет на партицию, что такое горячий ключ.
- Consumer group и потолок параллелизма.
- At-least-once и at-most-once через момент коммита, что такое lag.
acks, ISR,min.insync.replicas, идемпотентный продюсер и транзакции.