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

1. Разбиение на разделы в темах Kafka

Что такое «разделы»?

Темы Kafka разделяются на разделы  —  фундаментальные единицы масштабируемости и параллелизма. Каждый раздел  —  это упорядоченная, неизменяемая последовательность записей с возможностью их добавления.

Разбиение на разделы. Для чего?

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

Взаимодействие отправителя и раздела

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

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

Взаимодействие получателя или группы получателей и раздела

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

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

2. Проблемы динамического масштабирования разделов

Динамическое масштабирование разделов

Добавление новых разделов чревато проблемами. И вот почему.

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

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

Почему это происходит?

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

3. Избыточность данных и репликация разделов

Механизм репликации Kafka

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

Лидер и последователи: в разделе одна реплика  —  лидер, ею обрабатываются все считывания и записи. Другие реплики  —  последователи, ими данные реплицируются из лидера. Если случается сбой лидера, лидером становится один из последователей.

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

Репликация в действии

Синхронная репликация: последователями данные реплицируются из лидера синхронно: копируются, как только записываются им.

Набор синхронизированных реплик: это все реплики, актуализированные с лидером. Отстающая реплика удаляется из набора синхронизированных и не становится лидером, пока отставание не ликвидируется.

4. Гарантии доставки: минимум одна, максимум одна, ровно одна

Гарантии доставки

Для управления процессом обработки данных в Kafka предоставляется три уровня гарантий доставки.

Максимум одна: сообщения доставляются однажды или не доставляются вообще. Повторов нет, при сбое сообщения теряются. Хорош для сценариев, где потери допустимы.

Минимум одна: сообщения повторяются до подтверждения, поэтому не теряются. Однако это чревато дублями, если сообщение подтверждено, но до обработки случается сбой получателя.

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

Настройка отправителей и получателей для гарантий доставки

Конфигурации отправителей

  • acks=0: отправителем не ожидается подтверждения, максимум одна.
  • acks=1: отправителем ожидается подтверждение от лидера, минимум одна.
  • acks=all: отправителем ожидается подтверждение от всех синхронизированных реплик, минимум одна или ровно одна с идемпотентностью.
  • Идемпотентность: с включенной идемпотентностью каждое сообщение доставляется в тему лишь однажды, дубли предотвращаются.

Конфигурации получателей

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

Ровно одна с явным управлением смещениями и isolation.level=read_committed: для достижения семантики ровно одной доставки получателями.

  1. Отключается автофиксация: автофиксация смещений в Kafka предотвращается заданием enable.auto.commit=false. Получателем контролируется фиксация смещений, они фиксируются только после обработки сообщений.
  2. Явно фиксируются смещения: ручными фиксациями смещений, например commitSync() или commitAsync(), после обработки каждого сообщения или пакета сообщений. Так смещения фиксируются только после завершения обработки, в случае сбоев повторная обработка предотвращается.
  3. Используется isolation.level=read_committed: в конфигурации получателя задается isolation.level=read_committed. Этим параметром обеспечивается считывание получателями только зафиксированных сообщений как части успешной транзакции. И это важно для семантики ровно одной доставки, поскольку предотвращается считывание получателем незафиксированных или прерванных транзакций, которое чревато несоответствиями обработки.

5. Управление смещениями и согласованная обработка сообщений

Управление смещениями

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

Как управляются смещения

Смещения фиксируются получателями после обработки сообщений и сохраняются в специальном разделе Kafka __consumer_offsets или во внешней системе.

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

Важность управления смещениями

Согласованность: при корректном управлении смещениями одно и то же сообщение не обрабатывается получателями многократно, это важно для обеспечения согласованности обработки.

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

6. Контроллер Kafka. Zookeeper и его роль

Контроллер Kafka

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

Zookeeper и его роль

Zookeeper  —  это внешняя служба для координирования Kafka. Ею управляются метаданные о брокерах, темах, разделах и выборе контроллера.

Почему Zookeeper?

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

Выборы лидеров: с помощью Zookeeper в Kafka выбирается контроллер, которым затем выбираются лидеры разделов.

Переход на KRaft, то есть Kafka Raft

В Kafka отказываются от Zookeeper, переходя на KRaft, встроенный протокол консенсуса для управления метаданными.

Почему именно KRaft? Им упрощается архитектура Kafka, повышается масштабируемость, уменьшается сложность операций  —  метаданные управляются прямо в Kafka.

7. Управление схемой данных, эволюция схем

Реестр схем и поддерживаемые форматы

Реестр схем не ограничивается Avro, им управляются схемы и для других форматов сериализации: буферы протокола Protobuf и JSON-схема. С реестром схем обеспечиваются согласованное управление схемами и их проверка в этих форматах, так что отправителями и получателями соблюдается общее определение схемы.

Обратная совместимость

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

Совместимости схем

Обратная: данные, записанные старыми схемами, считываются новыми. При развитии отправителей имеющиеся получатели не ломаются.

Прямая: данные, записанные новыми схемами, считываются старыми. Поэтому получатели обновляются раньше отправителей.

Полная: это обратная и прямая совместимость, отправители и получатели развиваются независимо друг от друга, не ломаясь.

Изменения схем

Добавление поля: 

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

Пример: добавление поля country со значением по умолчанию USA. Имеющиеся получатели, которыми это поле не распознается, не сломаются: ими по умолчанию используется.

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

Удаление поля:

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

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

Обработка сообщений на лету при изменениях схемы

Эволюция схем в реальном времени:

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

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

Рассматриваемые сценарии

Добавление поля со значением по умолчанию: корректное функционирование получателей, которыми применяется старая схема, продолжится  —  новое поле ими игнорируется. Это справедливо для Avro, Protobuf и JSON при использовании реестра схем, пока в новом поле имеется значение по умолчанию.

Добавление поля без значения по умолчанию: прежде чем отправителями начнется применение новой схемы, получателям необходимо обновиться для работы с новым полем. Иначе сообщения отклоняются или случаются ошибки обработки. В Avro, Protobuf и JSON-схеме в этом сценарии требуется тщательно контролировать, чтобы получатели обновлялись синхронно с изменениями схемы.

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

Дополнительные замечания по Avro, Protobuf и JSON-схеме

  • Avro:

Отличается компактным двоичным кодированием, надежной поддержкой схем. Реестр схем легко интегрируется с Avro, при этом обеспечиваются надежные проверки схем и совместимости.

  • Protobuf:

Активно применяется благодаря своей эффективности и платформонезависимости. При использовании с реестром схем для Protobuf доступен функционал эволюции схем, аналогичный Avro, с обратной и прямой совместимостью.

  • JSON-схема:

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

Расширенное применение Kafka

Политики сжатия и хранения сообщений: управление хранилищем и актуальность данных

Политики хранения:

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

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

Сжатие сообщений:

Что такое «сжатие»?

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

Принцип работы сжатия:

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

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

Зачем нужно сжатие?

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

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

Kafka Streams для обработки в реальном времени

Введение в Kafka Streams

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

Основные понятия

Поток: непрерывный поток записей или сообщений из темы Kafka.

KStream и KTable: основные абстракции Kafka Streams. KStream  —  это поток записей, а KTable  —  поток журнала изменений, где каждая запись является обновлением.

Почему Kafka Streams?

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

Обработка с сохранением состояния: в Kafka Streams поддерживаются операции с сохранением состояния: оконная обработка, в частности агрегирование данных по временным интервалам, и объединения потоков.

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

Сценарии для Kafka Streams

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

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

Аналитика и агрегирование: расчет статистических данных реального времени, например скользящих средних или агрегирование данных о продажах.

Безопасность и соответствие требованиям

Функционал безопасности Kafka

Шифрование: в Kafka для защиты передаваемых данных поддерживается шифрование SSL/TLS. Благодаря этому данные, передаваемые между отправителями, получателями и брокерами, нельзя перехватить или скомпрометировать.

Аутентификация: в Kafka поддерживаются механизмы аутентификации на основе SSL и SASL, поэтому доступ в кластер здесь разрешен только авторизованным пользователям и приложениям.

Авторизация и списки контроля доступа: в Kafka списками управления доступом задаются разрешения на чтение, запись или управление темами, обеспечивается детализированный контроль доступа: операции над ресурсами Kafka выполняются только разрешенными клиентами.

Соответствие требованиям

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

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

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

Мониторинг и наблюдаемость

Важность мониторинга Kafka

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

Инструменты мониторинга Kafka

Prometheus и Grafana: Prometheus  —  это мощная система мониторинга для извлечения JMX-метрик Kafka. Они отображаются на визуальном дашборде Grafana  —  мониторить работоспособность и производительность кластера здесь проще.

JMX-метрики Kafka: управленческими расширениями Java Management Extensions предоставляются разнообразные метрики для диагностики проблем и оптимизации производительности: работоспособность брокера, состояние разделов темы, запаздывания получателей и другие.

Kafka Manager и Control Center: этими инструментами пользовательского интерфейса предоставляется информация о темах, брокерах и группах получателей Kafka, при помощи которой визуализируются метрики кластера, контролируются конфигурации тем, отслеживаются запаздывания получателей.

Что мониторится в Kafka

Работоспособность брокеров: проверкой ЦП, расхода памяти и дискового ввода-вывода предотвращается перегруженность брокеров.

Распределение разделов: для равномерной балансировки нагрузки мониторится распределение разделов между брокерами.

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

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

Заключение

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

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи Manjula Piyumal: Mastering Kafka: Advanced Concepts Every Senior Software Engineer Should Know

Предыдущая статья7 недооцененных GitHub-проектов, которые могут быть полезны
Следующая статьяC++: практическое руководство по priority_queue