7 ошибок при использовании Apache Kafka
Apache Kafka в настоящее время очень популярен. Он используется как брокер сообщений, его можно расширить дополнительными инструментами (Kafka Streams, Kafka Connect, Kafka Schema Registry) и стать полноценной платформой для передачи и обработки большого количества сообщений.
Мы расскажем о 7 наиболее распространенных ошибках при использовании Kafka и как их избежать
Ошибка 1
Использовать настройки по умолчанию
Отправка сообщения в несуществующий topic Kafka по умолчанию приводит к его созданию. К сожалению, настройки по умолчанию определяют единственный partition и коэффициент репликации 1. Они совершенно неприемлемы для использования в prod из-за возможной потери данных и ограниченной масштабируемости. Более того, эти настройки влияют на различные служебные топики Kafka
Как избежать этого?
Во-первых, вы можете отключить конфигурационные параметр auto.create.topics.enable (на уровне брокера), тогда каждую тему придется создавать явно, вручную
Другой способ - переопределить default.replication.factor и num.partitions (на уровне брокера), чтобы изменить значения по умолчанию для автоматически создаваемых topic
Ошибка 2
Давайте пока установим 1 partition для топика и изменим его позже Каково правильное количество partition? Это довольно сложный вопрос, который задают все, когда им нужно определить конфигурации для новых топиков. К сожалению, на него нет простого ответа, есть только рекомендации
Во-первых, давайте определим нижнюю границу. Количество partitions определяет максимальное количество consumers в одной consumer group. Если мы определим слишком маленькое число, то partitions будут расположены не на всех брокерах, что приведет к неравномерной загрузке кластера. Это означает, что максимальная скорость потребления сообщений и скорость генерации сообщений в топике зависят от количества partitions в топике.
Большое количество partitions влияет на различные процессы. Publishers буферизируют сообщения, отправляемые в Kafka, для каждого partition отдельно. Большее количество partitions означает меньшую вероятность того, что сообщения с разными ключами попадут в один и тот же partition, это означает меньшую вероятность неравномерной загрузки partition. Кроме того, больше partition = больше отдельных буферов = больше потребляемой памяти
Со стороны broker больше partitions означает большее количество открытых файловых дескрипторов. С другой стороны, у каждого partition есть лидер, которого выбирает Kafka Controller. Если одновременно необходимо выбрать несколько новых лидеров (например, из-за сбоя брокера), то контроллер может принимать "решения" с большой задержкой, а разделы могут быть недоступны в течение длительного времени. Например, процесс выбора лидера для 1000 partitions занимает около 5 секунд
Допустим, вы решили установить некоторое количество "временных" partitions и позже изменить их размер. Однако partition по умолчанию для сообщений с заданным ключом вычисляет хэш от ключа по модулю количества partitions. Когда количество разделов изменится, то сообщения с тем же ключом могут начать помещаться в другой partition. Такое изменение может привести к изменению порядка сообщений (для заданного ключа) при изменения количества partitions для топика
Так какое же число является оптимальным? Чтобы это понять, следует провести несколько тестов производительности. Смоделируйте нагрузку, подключите consumers и проверьте, какое количество partitions позволит достичь необходимой производительности
Ошибка 3
Используем конфигурации publisher по умолчанию
Для того, чтобы Kafka producer заработал, необходимо определить фактически только 3 конфигурационных ключа - bootstrap-серверы, сериализаторы ключей и значений. Однако зачастую этого недостаточно. Kafka включает в себя множество настроек, которые могут повлиять на порядок обмена сообщениями, производительность или вероятность потери данных
Например
1
acks - определяет, сколько реплик в синхронизации должны подтвердить сообщение (по умолчанию только лидер partition, что может привести к потере данных, поскольку лидер не ждет записи данных на диск, а только в кэш файловой системы)
2
retries - определяет количество повторных попыток при неудачной отправке
3
max.in.flight.requests - определяет максимальное количество неподтвержденных запросов, которые может обрабатывать клиент. Может влиять на порядок сообщений
Более того, producer собирает все сообщения, которые были отданы ему для отправки, в буферы для каждого partition. Это означает, что можно быть уверенным, что сообщение действительно отправлено, когда пришел ack или завершился соответствующий Future.
Ошибка 4 - Используем базовый Java-Consumer
Java-клиент Kafka является довольно мощным, но у него не лучший API. Использование Java Consumer может доставлять неудобства. Во-первых, класс Kafka Consumer может использоваться только одним потоком. Затем необходимо определить вечный цикл, который будет опрашивать брокер на наличие сообщений. Однако самым важным является то, как работают таймауты и heartbeats
За heartbeat отвечает дополнительный поток, он периодически посылает сообщение брокеру, чтобы показать, что он работает. Для Kafka нужно еще кое-что. Настройка max.poll.interval.ms (по умолчанию 5 минут) определяет максимальное время между hearbeats. Если оно будет превышено, то consumer будет исключен из consumer group. Это очень важно! Допустим, вы потребляете сообщения и отправляете их какому-то внешнему REST API. В случае неудачи отправки вы можете использовать экспоненциальный откат. Если пройдет более 5 минут, то ваш consumer покинет consumer group, а сообщение будет доставлено другому consumer из этой же consumer group. Самый простой способ избежать такого сценария - ограничить количество сообщений, получаемых за один вызов
Что можно использовать вместо стандартного Java-клиента? Есть несколько:

  • Spring для Apache Kafka
  • Alpakka Kafka - который предлагает API как на Java, так и на Scala.
  • FS2 Kafka - Scala lib для интеграции Kafka с FS2
  • Micronaut Kafka
  • Quarkus Kafka
  • и другие
Заблуждение 5 - Наш бизнес требует гарантии доставки exactly once
Обычно, когда вы спрашиваете своего клиента, какая семантика доставки приемлема для него, вы, разумеется, слышите ответ: ровно один раз. Затем вы немного гуглите и увидите замечательные заголовки, утверждающие, что Kafka поддерживает семантику exactly once! Отчасти это правда, но с теоретической точки зрения не существует такой вещи, как exactly once delivery...
В случае с Kafka (как и с любой другой распределенной системой) существуют ограничения на exactly once. Нужно включать специальные настройки на стороне producer (например, enable.idempotence, который требует определенных значений для max.in.flight.requests.per.connection, retries и acks). На стороне сonsumer это сложнее. Из-за сбоев передачи сообщений, падения consumer можно получить сообщение более одного раза, и тогда придется заниматься дедупликацией на уровне consumer. Что в любом случае приводит нас к идемпотентному consumer
Заблуждение 6
Кого волнует мониторинг, если система работает?
Kafka Cluster - это распределенная система. В подобных системах очень многое может пойти не так. Мониторинг необходим, чтобы знать, все ли работает так, как нужно, и узнавать о проблемах заранее по их косвенным признакам.

Могут возникать проблемы синхронизации реплик. В худшем случае это может привести к недоступности сервиса или даже потере данных.
Если вы действительно не хотите потерять данные или потерять доступность, вам следует использовать метрики Kafka. Существуют различные инструменты, которые позволяют экспортировать их довольно легко (посмотрите на JMX или Kafka Exporters)
Ошибка 7
Обновление зависимостей проекта без просмотра примечаний к релизу
Начиная с версии Kafka 0.11 клиенты обычно совместимы как с более ранним, так и с более поздними версиями брокеров Kafka. Когда выходят новые версии, процесс обновления довольно прост. Но иногда изменение версии может привести к большим проблемам
В качестве примера рассмотрим релиз 2.1.0. Это версия, в которой KIP-91 Intuitive Producer Timeout влияет на значение по умолчанию параметра Producer retry. Оно было изменено с 0 на Integer.MAX_VALUE. Кроме того, был добавлен новый таймаут для producer. Это изменение включило повторные попытки по умолчанию, что с добавлением max.in.flight.request.per.connection >1 (по умолчанию 5) может привести к переупорядочиванию сообщений
Kafka - очень мощный инструмент, однако использовать его нужно с умом. Следование рекомендациям из статьи позволит избежать неожиданных проблем. Внимательно проверьте, какие настройки используются для брокеров, topics, producers и consumers. После деплоя наблюдайте и определяйте оповещения по наиболее важным метрикам Kafka, чтобы убедиться, что система работает как вы задумано
Присоединяйтесь к нам в INSTAGRAM
]
[