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

Что такое тема в Apache Kafka?

Сообщения в Kafka организованы по темам. Тема - это именованный логический канал между производителем и потребителями сообщений. Имя обычно используется для описания данных, содержащихся в теме.

Примером темы может быть тема, содержащая показания всех датчиков температуры в здании под названием 'temperature_readings', или тема, содержащая GPS-координаты транспортных средств с автостоянки компании под названием 'vehicle_location' .

Производитель пишет сообщения в тему, а потребитель читает их из темы. Таким образом мы разделяем их, поскольку производитель может писать сообщения в тему, не дожидаясь потребителя. Затем потребитель может потреблять сообщения в своем собственном темпе. Это известно как шаблон публикации-подписки.

Кафка Рекорд

На языке кафка сообщения называются записями. Каждая запись состоит из ключа и значения, причем ключ не является обязательным.

Ключ записи используется для разделения записи, но мы скоро вернемся к этому.

Значение записи будет содержать данные, которые вы хотите отправить потребителю (ям). В случае нашей темы temperature_readings значением может быть объект JSON, содержащий, например, идентификатор датчика, значение температуры и отметка времени считывания. В случае нашей темы vehicle_location значением может быть двоичный объект, содержащий, например, идентификатор транспортного средства, текущая широта и долгота, а также время отправки местоположения.

Хранение записей

Одна вещь, которая отличает Kafka от других систем обмена сообщениями, заключается в том, что записи не удаляются из темы после их использования. Это позволяет нескольким потребителям использовать одну и ту же запись, а также позволяет одному и тому же потребителю читать записи снова (и снова).

«Так когда же тогда записи удаляются из темы?» вы можете спросить. Они удаляются через определенный промежуток времени. По умолчанию Kafka хранит записи в теме 7 дней. Удержание можно настроить для каждой темы.

Раздел

В теме будет один или несколько разделов. Разделение - это очень простая структура данных. Это последовательность записей, предназначенная только для добавления, полностью упорядоченная по времени добавления.

Давайте разберемся с этим немного. Если мы говорим, что раздел начинается с левой стороны, то новые записи всегда будут добавляться справа от последней записи. В приведенном выше примере новая запись будет добавлена ​​после 4-й записи. Это позволяет потребителям читать записи в том же порядке, в котором они были созданы (в нашем случае слева направо).

Только добавление означает, что записи не могут быть изменены после их записи.

Идея структурированного журнала фиксации недалека от журнала приложения. Новая строка всегда добавляется в конец файла, и после того, как строка записана в журнал, ее нельзя изменить.

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

Если собрать все вместе, тема выглядит примерно так:

Здесь нужно помнить несколько вещей:

  • Записи всегда добавляются в конец раздела. Это означает, что в одном разделе записи с меньшим смещением старше.
  • Смещение (и порядок записей) имеет значение только внутри раздела.
  • Сообщения, отправленные производителем в определенный раздел темы, будут добавляться в порядке их отправки.
  • Экземпляр-потребитель видит записи в том порядке, в котором они хранятся в разделе.
  • Записи с одним и тем же ключом всегда попадают в один и тот же раздел (подробнее об этом в следующем разделе).

Связь между записью и разделом

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

Почему это важно?

Иногда нам нужно доставлять записи потребителям в том же порядке, в котором они были созданы. Когда покупатель покупает, например, электронную книгу из вашего интернет-магазина, а затем отменяет эту покупку, вы хотите, чтобы эти события приходили в том порядке, в котором они были созданы. Если вы получите событие отмены до события покупки, отмена будет отклонена как недействительная (поскольку покупка еще не существует в системе), а затем система зарегистрирует покупку, доставит продукт покупателю (и потеряет вас Деньги).

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

Таким образом, записи с одним и тем же ключом попадают в одни и те же разделы. Но учтите, что один раздел может содержать записи с более чем одним ключом, так что не стоит сходить с ума с количеством разделов :).

Выше вы видите пример темы с двумя разделами. Ключи записей имеют строковый тип, а значения записей имеют целочисленный тип. В этом примере вы заметите, что все записи с ключами k1 и k3 записываются в раздел 0, а записи с ключами k2, k4 и k5 отправляются в раздел 1.

Что происходит, когда ключ записи равен нулю?

Как я упоминал ранее, указывать ключ при создании записи Kafka не обязательно. Если ключ равен нулю, производитель выберет раздел циклическим способом. Итак, если вам не нужно упорядочивать записи, вам не нужно помещать ключ в запись Kafka.

Хорошо, а зачем нам перегородки?

В Kafka разделение имеет несколько целей.

С точки зрения брокера Kafka, разделы позволяют распределить одну тему по нескольким серверам. Таким образом, в теме можно хранить больше данных, чем может вместить один сервер. Если вы предполагаете, что вам нужно хранить 10 ТБ данных в теме и у вас есть 3 брокера, одним из вариантов будет создание темы с одним разделом и хранение всех 10 ТБ на одном брокере. Другой вариант - создать тему с 3 разделами и распределить 10 ТБ данных по всем брокерам.

С точки зрения потребителя раздел - это единица параллелизма.

Как это сейчас?

Вот пример, объясняющий это: допустим, производитель отправляет 2000 записей каждую секунду в тему vehicle_location, о которой мы упоминали ранее. Теперь предположим, что у нас есть микросервис, потребляющий данные, который выполняет тяжелые вычисления для каждого сообщения и может обрабатывать только 1000 сообщений в секунду.

В этом сценарии наш потребитель будет постоянно отставать и никогда не сможет догнать производителя. Итак, как решить эту проблему?

Мы могли создать тему с 3 разделами. Таким образом мы получим около 700 сообщений в секунду на каждый раздел. Затем мы развернем 3 экземпляра нашего потребительского микросервиса, где каждый экземпляр читает из одного раздела.

Теперь каждый экземпляр-потребитель обрабатывает 700 сообщений в секунду, и все экземпляры вместе легко не отстают от производителя. Вот что мы имеем в виду, когда говорим, что раздел - это единица параллелизма: чем больше разделов имеет тема, тем больше обработки может выполняться параллельно. Как это достигается - тема другого поста. А пока достаточно понять, чем помогают разделы.

Репликация темы

Kafka - это распределенная и отказоустойчивая система. Один из способов достижения этого - репликация данных между брокерами. Когда мы создаем тему, нам нужно указать коэффициент репликации. Это сообщает Kafka, сколько раз ему следует реплицировать разделы между брокерами, чтобы избежать потери данных в случае сбоев. Обратите внимание, что коэффициент репликации не может быть больше, чем количество брокеров, иначе вы не будете распределять данные так часто, как копируете их в другое место на том же жестком диске 🙂

Вот пример темы с тремя разделами и коэффициентом репликации 2 (это означает, что каждый раздел дублируется). Это показывает возможное распределение разделов (фиолетовым цветом) и их реплик (зеленым цветом) по брокерам. Kafka гарантирует, что одни и те же разделы никогда не попадут на одного и того же брокера. Это необходимо для предотвращения сбоев сервера без потери данных.

Кроме того, Kafka гарантирует, что «для темы с фактором репликации N он выдержит до N-1 сбоев сервера без потери каких-либо записей, зафиксированных в журнале». Таким образом, в нашем примере с коэффициентом репликации 2 мы можем потерять любого отдельного брокера, и у нас все равно будут все разделы, доступные как для записи, так и для чтения.

Лидер и последователи раздела

Для каждого раздела будет один брокер, который является лидером для этого раздела. В нашем случае брокер с фиолетовым разделом является лидером для этого раздела. Остальные брокеры будут подписчиками (зеленые разделы). Итак, в приведенном выше случае брокер 1 является лидером для раздела 0 и ведомым для раздела 1.

Все операции записи и чтения идут к лидеру раздела, в то время как последователи просто копируют данные для синхронизации с лидером. Последователь, который синхронизируется с лидером, называется синхронизированной репликой (ISR). Если лидер для раздела отключен, одна из синхронизированных реплик будет выбрана в качестве нового лидера, и все производители и потребители начнут разговаривать с новым лидером.

Вот и все, основы тем и разделов Kafka. Не волнуйтесь, если вам понадобится время, чтобы понять эти концепции. Не стесняйтесь добавить этот пост в закладки и вернуться позже, чтобы перечитать его при необходимости.

И если вам понравилась эта статья, не забудьте поделиться!

Хотите узнать больше о Кафке?

Я создал мини-курс Kafka, который вы можете получить абсолютно бесплатно. Подпишитесь на это в Coding Harbour.

Первоначально опубликовано на https://codingharbour.com.