August 13, 2023

Простым языком об Apache Kafka, как, зачем и почему

В данной статье я хочу попытаться рассказать максимально доступно и просто о такой непростой технологии как Apache Kafka. Расскажу о том:

  • Кем и зачем она была создана.
  • Доступно рассмотрим из каких абстракций и примитивов состоит.
  • За счет чего достигается высокая пропускная способность.
  • Поговорим про отказоустойчивость и за счет чего она достигается.

Многие новички часто задают вопрос "Почему?" касаемо любой новой технологии. Надеюсь что этой статьей я смогу ответить на большинство “Почему?” связанных с Apache Kafka.

Краткий экскурс в историю. Причины появления Kafka

Apache Kafka — распределенный, реплицируемый журнал с открытым исходным кодом, разрабатываемый в рамках фонда Apache. Написан на Java и Scala. Сложно, непонятно, но пойдем дальше.

Разработан в компании LinkedIn в начале 2010х, далее был передан в фонд Apache. Сейчас авторы проекта работают в компании Confluent которую сами и основали.

Kafka зародилась в LinkedIn как решение для задач про передаче больших объемов данных между сервисами, в частности для построения моделей машинного обучения. Классические брокеры сообщений не могли обеспечить нужную пропускную способность (throughput) и LinkedIn решил создать “свой велосипед”

Из чего состоит Apache Kafka?

Что же придумали разработчики Kafka чтобы достигнуть высокой скорости передачи данных? Ответ: сделали брокер максимально простым и топорным: он хранит все сообщения на диске и позволяет делать с ними только 2 простых но очень эффективных с точки зрения железа операции:

  • добавить запись в конец файла
  • прочитать файл с позиции X до позиции Y

Как следствие, нельзя:

  • искать, фильтровать данные на стороне кластера, только на стороне клиента
  • удалять данные (за удаление данных отвечает Kafka)

За чтение сообщений отвечают потребители (consumers).За отправку сообщений в Kafka отвечают производители (producers). Писатель и читатель при взаимодействии с брокером указывают обязательный параметр - topic или тема. За счет него логически идет разделение потоков данных на стороне kafka.

Чуть подробнее о потребителях

Потребитель по порядку читает сообщения из темы и направляет брокеру Kafka специальные сообщения о том что он прочитал. В этом самом сообщении брокеру передается специальный идентификатор offset - позиция на которой остановился читатель.

Если читатель перезапускается то при повторном подключении к брокеру он получит последнее актуальное состояние offset и продолжит читать сообщения с того места на котором остановился. Offset в каком то смысле похож на индекс в массиве. Зная индекс мы можем сразу обратиться к нужному элементу и продолжить обработку всех последующих за ним.

И это всё? Просто файлы?

На самом деле нет. Представим, у нас есть топик X, в который пишется очень много сообщений. Мы понимаем что в одного потребителя не справляемся и хотим распаралелить процесс. Если наш topic это просто файл то читать из него несколькими потребителями становится проблематично, так как нужно потребителей синхронизировать между собой, чтобы не получилось так что каждый потребитель обрабатывает одно и то же. Синхронизация это время, и оно очень ценно, с ростом количества потребителей время синхронизации будет линейно расти.

Что же делать? Разработчики Kafka решили разделить топик на N независимых сущностей (по факту это те же файлы) назвав партициями. Теперь нас ничто не останавливает от того чтобы создать N потребителей и быстро вычитывать данные, так как потребителей не нужно синхронизировать, каждый читает только свой кусочек, свою партицию.

Мы достигли цели, пропускная способность за счет деления топика на партиции способна расти линейно, успевай добавлять партицию и потребителей.

Набор потребителей в Kafka именуется Consumer Group (группа потребителей). При добавлении или выходе потребителей из группы kafka требуется ребалансировка, чтобы либо выделить новому потребителю свою партицию либо назначить уже работающему консьюмеру партицию которую читал умерший консьюмер.

Что насчет отказоустойчивости?

Репликация

Что может пойти не так с Kafka брокером? Да всё что угодно, например сервер на котором он развернут может выйти из строя. В таком случае мы не сможем ни писать сообщения ни читать их, а это грусть печаль, бизнес стопорится, деньги не зарабатываются. Что спасает в таких случаях? Правильно, избыточность.

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

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

Репликация конфигурируется для каждого топика через переменную Replication Factor - сколько копий для партиции нужно иметь в кластере.

Controller

У одного узла в кластере Kafka есть специальная роль - controller, в его обязанности входит как раз таки на основании состояния кластера назначать лидеры для партиций топиков. Лидер партиция - партиция с которой взаимодействуют потребители и произовдители.  Аналог мастера в мире БД. Остальные копии лидер-партиции являются ведомыми и их обязанность - участвовать в репликации.

Для того чтобы гарантировать в кластере уникальность роли controller а также хранить и отслеживать состояние брокеров кластера Kafka использует kraft / Apache Zookeper.

Итог

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

Надеюсь у меня получилось доступно донести концепции и теперь вас не испугать популяным определением которую дают Kafka на просторах сети - распределенный, реплицируемый журнал