Как использовать Kafka на собеседовании по System Design

Данная статья не является всеобъемлющим разбором Kafka. Она рассматривает базовые концепции и предназначена для читателя, который готовится к интервью по System Design и хочет освежить свои знания.

Видеоверсию этой статьи на русском языке можно посмотреть здесь — https://www.youtube.com/watch?v=lDRx5dqQltA


Вы наверняка слышали о Kafka — это популярная распределенная платформа потоковой обработки событий с открытым исходным кодом. Согласно сайту проекта, ей доверяют около 80% компаний из списка Fortune 100. Если Kafka подходит крупным компаниям, значит, она вполне подойдет и на интервью по System Design.

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

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

Практический пример: мотивация к изучению Kafka

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

Заведем сервер с очередью и будем отправлять в нее сообщения по мере поступления событий. Сервер или процесс, ответственный за отправку событий в очередь, называется производителем (producer). Далее у нас есть сервер, который считывает события из очереди и обновляет сайт. Этот сервер называют потребителем (consumer).

Простой пример

Простой пример

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

Чтобы масштабировать эту систему, нам необходимо добавить больше серверов для распределения очереди. Но как убедиться, что события будут обрабатываться в правильном порядке?

Два сервера

Два сервера

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

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

Распределение событий по играм

Распределение событий по играм

Но что делать с нашим потребителем, который продолжает испытывать перегрузку? Здесь в игру вступает концепция группы потребителей (consumer group) Kafka. Каждое событие гарантированно обрабатывается лишь одним потребителем внутри группы.

Группа потребителей

Группа потребителей

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

Темы и разделы

Темы и разделы

Таким образом, потребители событий игр футбола подпишутся исключительно на тему футбола, а потребители баскетбола — на тему баскетбола.

Основные понятия и архитектура Kafka

Наш пример полезен для знакомства с технологией, однако давайте сформулируем ключевые термины и концепции Kafka.

Брокеры

Кластер Kafka состоит из множества брокеров (broker) — отдельных серверов (физических или виртуальных). Каждый брокер хранит данные и обслуживает клиентов. Чем больше брокеров, тем больше данных можно хранить и тем большее количество клиентов можно обслуживать.

Разделы

В каждом брокере есть несколько разделов. Раздел (partition) представляет собой упорядоченную неизменяемую последовательность сообщений, в которую сообщения только добавляются — своего рода файл журнала. Именно благодаря разделам Kafka масштабируется, позволяя организовать параллельную обработку сообщений.

Темы

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

Итак, в чем же отличие темы от раздела? Тема — это логическая группа сообщений. В то же время раздел — это физическая группа сообщений (раздел — это журнал сообщений внутри темы с поддержкой очередности событий). Тема может состоять из одного или нескольких разделов, и каждый из этих разделов может находиться на разных серверах (брокерах). Темы — это просто способ организовать ваши данные, тогда как разделы — это способ масштабировать ваши данные (разбив их на независимые друг от друга физические журналы — очереди).

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

Производители и потребители

Производители — это процессы, записывающие данные в темы, а потребители — процессы, читающие из них. Хотя Kafka предоставляет простой интерфейс для взаимодействия производителей и потребителей, создание и обработка самих сообщений ложится на разработчика. Kafka не заботится о содержании данных — она просто сохраняет и передает их.

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

Как работает Kafka?

При возникновении события производитель формирует сообщение (или запись — record) и отправляет его в тему Kafka. Каждое сообщение включает обязательное значение (value) и три необязательных: ключ (key), временную метку (timestamp) и заголовки (headers).

Структура сообщения

Структура сообщения

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

Рассмотрим простой пример отправки сообщения в тему с помощью инструмента командной строки Kafka:

kafka-console-producer --bootstrap-server localhost:9092 --topic my_topic --property "parse.key=true" --property "key.separator=:"
> key1: Привет, Kafka с ключом!
> key2: Другое сообщение с другим ключом

Флаги —property “parse.key=true” и —property “key.separator=:” указывают, что пары ключ-значение для сообщений разделяются символом двоеточия.

Также посмотрим на аналогичный пример с использованием библиотеки kafkajs для Node.js:

// Инициализация клиента Kafka
const kafka = new Kafka({
  clientId: "my-app",
  brokers: ["localhost:9092"],
});

// Инициализация производителя
const producer = kafka.producer();

const run = async () => {
  // Подключение производителя
  await producer.connect();

  // Отправка сообщений в тему 'my_topic' с ключами
  await producer.send({
    topic: "my_topic",
    messages: [
      { key: "key1", value: "Привет, Kafka с ключом!" },
      { key: "key2", value: "Другое сообщение с другим ключом" },
    ],
  });
};

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

  1. Определение раздела: Kafka применяет алгоритм хеширования ключа сообщения, назначая сообщение конкретному разделу. Если сообщение не имеет ключа, Kafka распределяет его, используя алгоритм round-robin или руководствуется другим механизмом, указанным в конфигурации. Это гарантирует, что сообщения с одинаковым ключом всегда попадают в один и тот же раздел, сохраняя порядок на уровне раздела.

  2. Назначение брокера: после выбора раздела Kafka определяет, какой брокер отвечает за этот раздел. Соответствие разделов конкретным брокерам управляется метаданными кластера Kafka. За этим следит контроллер Kafka (роль внутри кластера брокеров). Производитель использует эти метаданные для прямой отправки сообщения брокеру, содержащему целевой раздел.

Каждое сообщение в разделе Kafka представлено как запись в неизменяемом журнале. Сообщения последовательно добавляются в конец журнала, поэтому Kafka часто описывают как распределенный журнал записей (distributed commit log). Такая структура журнала лежит в основе архитектуры Kafka и обладает несколькими важными преимуществами:

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

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

  3. Масштабируемость: простота механизма добавления записей в журнал способствует горизонтальному масштабированию. Можно добавлять новые разделы и распределять их по нескольким брокерам для увеличения пропускной способности. Каждый раздел может быть реплицирован на множестве брокеров для повышения отказоустойчивости.

Каждое сообщение в разделе Kafka получает уникальное смещение (offset), определяющее позицию сообщения в разделе. Потребители используют этот идентификатор для отслеживания своего прогресса чтения сообщений из темы. По мере чтения сообщений потребители сохраняют свое текущее смещение и периодически подтверждают его обратно в Kafka. Так обеспечивается возможность возобновления чтения с места остановки в случае сбоя или перезагрузки. Обратите внимание: обычная схема с фиксацией смещения после обработки дает доставку at-least-once. Если потребитель выходит из строя после обработки сообщения, но до фиксации его смещения, сообщение будет обработано повторно после перезапуска. Доставка exactly-once возможна только при дополнительной настройке: идемпотентных производителях, транзакциях и аккуратной обработке на стороне потребителя.

Смещения (offsets)

Смещения (offsets)

С момента записи сообщений в указанный раздел Kafka поддерживает надежное хранение и доступность данных с помощью репликации. Эти гарантии зависят от настроек кластера и производителя. Репликация основана на модели лидера и последователей:

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

  2. Репликация последователей: помимо лидера, существует несколько реплик-последователей, расположенных на разных брокерах. Эти реплики копируют данные с лидера и могут стать новым лидером при его отказе.

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

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

Наконец, потребители извлекают сообщения из тем Kafka, используя модель вытягивания (pull-based model). В отличие от некоторых других систем доставки сообщений, где данные принудительно отправляются потребителям, Kafka оставляет выбор потребителю, позволяя ему самостоятельно запрашивать новые сообщения через определенные интервалы. Такой подход имеет несколько преимуществ: контроль над скоростью потребления; упрощенное управление ошибками; предотвращение чрезмерной загрузки медленных потребителей; возможность эффективного пакетного чтения.

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

kafka-console-consumer --bootstrap-server localhost:9092 --topic my_topic 
  --from-beginning --property print.key=true --property key.separator=": "

# Результат
key1: Привет, Kafka с ключом!
key2: Другое сообщение с другим ключом

Аналогичный пример на JavaScript с библиотекой kafkajs выглядит так:

// Инициализация клиента Kafka
const kafka = new Kafka({
  clientId: "my-app",
  brokers: ["localhost:9092"],
});

// Инициализация потребителя
const consumer = kafka.consumer({ groupId: "my-group" });

const run = async () => {
  // Подключение потребителя
  await consumer.connect();

  // Подписка на тему 'my_topic'
  await consumer.subscribe({ topic: "my_topic" });

  // Чтение сообщений
  await consumer.run({
    eachMessage: async ({ topic, partition, message }) => {
      console.log({
        value: message.value.toString(),
        key: message.key.toString(),
      });
    },
  });
};

Объединив все вместе, получаем следующую картину:

Кластер Kafka

Кластер Kafka

Использование Kafka в интервью

Kafka может использоваться как очередь сообщений или как система потоковой обработки.

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

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

  • Необходим асинхронный подход к обработке. Например, когда пользователи загружают видео на YouTube, мы можем немедленно сделать видео стандартного разрешения доступным, а затем поместить видео (по ссылке) в Kafka для перекодирования в асинхронном режиме.

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

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

Потоки полезны в следующих случаях:

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

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

Что нужно знать о Kafka для собеседований по проектированию систем

У Kafka есть много аспектов, но мы сосредоточимся на самых важных в рамках собеседования.

Масштабируемость

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

Хотя размер сообщения в Kafka не ограничен жесткими рамками (его можно настроить через параметр message.max.bytes), рекомендуется ограничиваться размером менее 1 МБ для оптимальной производительности, снижения нагрузки на память и оптимизации использования сети.

Распространенная ошибка в интервью по System Design заключается в хранении больших объемов данных в Kafka. Kafka не является базой данных, и она не предназначена для хранения крупных файлов. Она создана для обработки небольших сообщений, которые могут обрабатываться быстро. Например, при разработке YouTube нам необходимо производить пост-обработку загружаемых видеороликов, нарезая их на фрагменты и перекодируя. Простое решение могло бы заключаться в помещении самих видео в Kafka, чтобы рабочие процессы нарезки и перекодирования могли асинхронно извлекать их из очереди и обрабатывать. Это плохая идея. Вместо этого лучше хранить сами видео в распределенной файловой системе, такой как S3, а в Kafka помещать сообщение с указанием местоположения видео в S3. Таким образом, сообщение в Kafka остается небольшим и служит лишь указателем на полное видео в S3.

Хорошее железо позволяет одному брокеру хранить большие объемы данных (до 1 ТБ) и обрабатывать очень большой поток сообщений (до 1 млн в секунду). Точные числа зависят от размера сообщений, дисков, сети, числа разделов, настроек подтверждений и требований к задержке. Даже если одного брокера хватает по пропускной способности, кластер часто масштабируют ради отказоустойчивости, репликации и равномерного распределения нагрузки.

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

  1. Горизонтальное масштабирование с дополнительными брокерами: простейший способ масштабирования — добавить дополнительные брокеры в кластер. Это помогает распределить нагрузку и повысить устойчивость к отказам. Главное — убедитесь, что ваши темы имеют достаточное число разделов, чтобы воспользоваться новыми брокерами. Больше разделов позволит увеличить параллелизм и улучшить распределение нагрузки. Без достаточного числа разделов новый брокер останется невостребованным.

  2. Стратегия разделения данных: Основная задача при масштабировании Kafka — выбрать правильную стратегию распределения данных. Важнейшей частью решения является правильный выбор ключа сообщений. Алгоритм разделения основан на хешировании ключа (по умолчанию используется хеш-функция MurmurHash2) с последующим вычислением остатка от деления на число разделов (partition = hash(key) % num_partitions). Неправильный выбор ключа может привести к возникновению горячих разделов, перегруженных трафиком. Хорошими ключами являются равномерно распределенные ключи.

Стоит отметить, что вне рамок интервью многие проблемы масштабируемости решаются благодаря облачным управляемым сервисам Kafka, таким как Confluent Cloud или AWS MSK. Эти сервисы берут на себя большую часть вопросов масштабирования, но все равно важно понимать лежащие в их основе концепции.

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

Обработка горячих разделов

Интервьюеры любят проверять ваше понимание обработки “горячих” разделов. Рассмотрим ситуацию с Агрегатором рекламных кликов, где Kafka собирает потоки событий нажатий пользователями на объявления. Логичным решением было бы разделить события по идентификаторам объявлений. Но предположим, что корпорация X запускает новую рекламную кампанию, и соответствующий раздел оказывается перегруженным (“горячим”).

Существует несколько способов справиться с такой ситуацией:

  1. Случайное распределение без ключа: если не указывать ключ, Kafka произвольно назначает раздел сообщению, обеспечивая равномерное распределение. Недостатком является потеря гарантии порядка. Подходит, если порядок не играет роли.

  2. Добавление соли (random salting): ключ сообщения можно дополнить случайным числом или временной меткой. Это улучшит распределение нагрузки, хотя усложняет последующую агрегацию на стороне потребителя.

  3. Использование составного ключа: вместо простого идентификатора объявления используйте комбинацию, включающую географическое положение или сегменты пользователей. Этот подход помогает более равномерно распределять нагрузку и особенно полезен, если вы можете определить атрибуты, которые изменяются независимо от идентификатора объявления.

  4. Обратное давление (back pressure): в зависимости от требований, иногда проще замедлить темп поступления сообщений. Managed сервис Kafka может предложить встроенный механизм управления back pressure. Если вы используете собственный кластер Kafka, вручную проверяйте задержку раздела (partition lag) и замедляйте работу, если она слишком велика.

Отказоустойчивость и надежность

Одна из причин выбора Kafka — высокая гарантия сохранности данных. Но как именно Kafka защищает ваши данные и предотвращает потерю сообщений?

Устойчивость данных достигается за счет механизма репликации Kafka. Каждый раздел реплицируется на несколько брокеров, где один выступает в качестве лидера, а остальные — последователей. Сообщение, отправленное производителем, сначала сохраняется на ведущем экземпляре, а затем реплицируется на последователей. Благодаря этому даже при отказе брокера данные сохраняются. Настройки подтверждений производителя играют ключевую роль. Установка режима acks=all гарантирует, что сообщение подтверждается только после того, как все синхронные реплики (in-sync replicas, ISR) его получили, обеспечивая максимальную надежность.

Настройка коэффициента репликации ваших тем (replication factor) позволяет регулировать уровень отказоустойчивости. Коэффициент репликации равен числу копий каждого раздела. Типичное значение — 3, означающее наличие лидера и двух реплик. Поэтому даже при выходе из строя одного брокера данные останутся доступны на оставшихся, и одна из реплик сможет стать новым лидером.

Что произойдет, если откажет потребитель?

Kafka обычно воспринимается как устойчивая система. Часто говорят: “Kafka всегда доступна, иногда согласована.” Вопрос вроде “Что случится, если Kafka выйдет из строя?” не реалистичен, и вы можете мягко возразить интервьюеру, если услышите подобное.

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

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

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

Рассматривая компромисс между производительностью и устойчивостью, обратите внимание на выбор подходящего момента для фиксации смещений. Например, в задаче проектирования Web Crawler важно зафиксировать смещение только после успешного сохранения сырого HTML в объектное хранилище. Чем сложнее работа потребителя, тем выше вероятность повторной обработки после сбоев. Следовательно, лучше минимизировать сложность действий потребителя и разбить процесс на две фазы: скачивание HTML и последующий парсинг.

Обработка ошибок и повторных попыток (retries)

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

Повторные попытки производителя

Сначала рассмотрим сценарий, когда сообщение не удается отправить в Kafka. Ошибки могут возникать из-за проблем сети, недоступности брокера или временных сбоев. Чтобы смягчить последствия, Kafka-производители поддерживают автоматические повторы. Вот пример конфигурации производителя:

const producer = kafka.producer({
  retry: {
    retries: 5, // Повторить до 5 раз
    initialRetryTime: 100, // Ждать 100мс между повторами
  },
  idempotent: true,
});

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

Повторные попытки потребителя

Со стороны потребителя ситуация немного сложнее. Поскольку Kafka не поддерживает повторные попытки из коробки (в отличие от AWS SQS), необходимо разработать собственную логику обработки ошибок. Один из популярных подходов — создать отдельную тему для неудачных сообщений и отдельный потребитель для их обработки. Таким образом, можно повторять попытки столько раз, сколько потребуется, не влияя на основной поток. Если какое-то сообщение многократно терпит неудачу, оно перемещается в специальную очередь сообщений (Dead Letter Queue, DLQ), где его можно проанализировать позднее.

Повторные попытки потребителя и DLQ

Повторные попытки потребителя и DLQ

Оптимизация производительности

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

Первое, что можно сделать — объединять сообщения в пакеты перед отправкой в Kafka. В kafkajs для этого обычно отправляют несколько сообщений одним вызовом send() или используют sendBatch().

await producer.send({
  topic: "my_topic",
  messages: [
    { key: "key1", value: "Первое сообщение" },
    { key: "key2", value: "Второе сообщение" },
  ],
});

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

await producer.send({
  topic: "my_topic",
  compression: CompressionTypes.GZIP,
  messages: [{ key: "key1", value: "Сжатое сообщение" }],
});

Одним из важнейших факторов производительности остается правильный выбор ключа сообщения. Цель — максимизировать параллелизм, равномерно распределяя сообщения по разделам. На это обязательно нужно обратить внимание в ходе интервью.

Политики хранения данных (Retention Policies)

Каждая тема Kafka имеет политику хранения, определяющую срок хранения сообщений в журнале. Параметры настройки включают retention.ms и retention.bytes, и по умолчанию сообщения хранятся 7 дней.

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

Заключение

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

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


Разборы задач по System Design:

Ticketmaster, Uber, Tinder, Dropbox, Rate Limiter


Автор: pavsenin

Источник

Оставить комментарий