Введение

Введение

Глоссарий

  • Producer - отправитель сообщений
  • Consumer - получатель сообщений
  • Broker - сущность отвечающая за получение данных от Producer и отправку их в Consumer
  • Topic - аналог очереди в Rabbit
  • Partition - независимая часть Topic
  • Segment - единица деления Partition на физическом носителе
  • Offset - номер сообщения/события в брокере Kafka
  • Base offset - начальный номер сообщения в сегменте
  • Controller - координирует работу кластера брокеров
  • ISR (in sync replica) - реплика, синхронизированная с лидером
  • Commit offset - значение последнего оффсета, обработанного Consumer

Отличия от RabbitMQ

  • В Rabbit брокер пушит сообщения в консьюмера. В Kafka консьюмер сам забирает сообщения из брокера (poll)

Архитектура Kafka Topic

Topic

attachments/Снимок экрана 2023-07-28 в 15.11.24.png
Topic делится на партиции (partition). Все партиции независимы, данные пишутся всегда в конец партиции. Сообщения в партиции номеруются по порядку с 0. Номер называется оффсетом (offset) сообщения.

Partition

Вся партиция целиком находится на одном физическом носителе. Но находится она не одним куском данных, а делится на сегменты (segment).

attachments/Снимок экрана 2023-07-28 в 15.13.55.png
Запись всегда идет в последний сегмент, который называется активным сегментом. Номер начального события в сегменте называется базовым оффсетом (base offset)

Удаление данных

Данные мы можем удалять только целыми сегментами.

На партицию можно настроить ограничение по размеру:

retention.bytes=-1 # По умолчанию нет ограничения

И ограничение по времени:

retention.ms=604800000 # По умолчанию 7 дней

Кафка смотрит на время жизни сегментов и удаляет самые старые, если их время жизни истекло.

Segment

Структура сегмента выглядит следующим образом:
attachments/Снимок экрана 2023-07-28 в 15.52.07.png
У каждого сегмента хранится 3 файла: название файла содержит базовый оффсет.

  • Данные хранятся в .log файле. События в нем хранятся последовательно, файл работает только на добавление данных в конец.
    attachments/Снимок экрана 2023-07-28 в 15.57.58.png

  • В файле .index хранятся данные для быстрого доступа к оффсетам внутри log-файла.

    Index record = (relative offset, position)
    
  • В файле .timeindex хранятся данные для быстрого доступа по времени

Архитектура Kafka Broker

attachments/Снимок экрана 2023-07-29 в 11.58.37.png

Каждая партиция на брокере может быть реплицированна. например, с replication factor = 3 и тремя брокерами на каждом брокере будет по одной репликации каждой партиции.

Для того, чтобы записывать на реплицированную партицию, должен быть выбран лидер на одном из брокеров. Лучше выбирать лидеров равномерно по брокерам, так как лидер несет большую нагрузку, так как на них идет начальная запись.

После записи на лидера начинается процесс синхронизации других реплик с лидером. Реплика, синхронизированная с лидером, называется ISR (in sync replica). ISR может участвовать в перевыборе нового лидера, в случае сбоя старого.

[!info]
Если в случае экстренных перевыборов лидеров кластер оказался неравномерным по кол-ву лидеров на брокерах, то Кафка автоматически начнет перебалансировку прозрачно для пользователей.

Архитектура Kafka Producer

Для отправки сообщений можно задать различные уровни гарантий доставки:

enum Acks : int {
  None = 0,   // Нет гарантий 
  Leader = 1, // Гарантия, что сообщение записано на лидер
  All = -1    // Гарантия, что сообщение записано на все реплики
}

Кол-во реплик, нужных для статуса All может быть задано настройкой топика:

min.insync.replicas = 2 // Достаточно записи на двух репликах

Производительность

В Kafka сообщения отправляются пачкой, для того, чтобы сконфигурировать параметры этой пачки имеются несколько настроек:

  • BatchSize - максимальный размер пачки в байтах
  • BatchNumMessages - максимальный размер пачки в кол-ве сообщений
  • LingerMs - максимальное время, которое мы ожидаем до добавления следующего сообщения в пачку

Если срабатывает хотя бы одно из этих ограничений, то пачка отправляется в брокер. Таким образом можно настраивать продюсера на низкую задержку или на большую пропускную способность.

Архитектура Kafka Consumer

Commit

Консьюмер считывает сообщения из брокера пачками и отдает клиенту их по одному. Клиент обрабатывает сообщение и отправляет Commit обратно в брокер. Commit со значением оффсета сообщения складывается в специальный топик в брокере. Таким образом, если консьюмер упадет, то ему не придется перечитывать все сообщения с нуля.

Это гарантия доставки at least once - мы можем обработать сообщение и упасть, не успев отправить коммит.

Коммит на каждое сообщение не очень эффективен, так как мы сильно увеличиваем траффик. Для решения этой проблемы, у Kafka есть режим 1 коммит на N сообщений. Также, есть возможность делать асинхронные авто-коммиты по времени:

EnableAutoCommit=true
AutoCommitIntervalMs=5000

Если появляется новый консьюмер и у него еще нет коммит оффсета, то он может настроить какое первое сообщение из топика он хочет получить:

enum AutoOffsetReset {
  Latest = 0,   // берем последнее сообщение
  Earliest = 1, // берем первое сообщение
  Error = 2     // Возвращаем ошибку. 
}

Consumer Group

Коньсюмеры объединенные в одну группу могут делить чтение сообщений. Kafka автоматически балансирует части, которые будут читать разные консьюмеры в группе.

Чего нет в Kafka из коробки

  • Отложенные сообщения
  • Dead Leter Queue
  • AMQP / MQTT
  • TTL на одно сообщение
  • Очереди с приоритетами