Какие проблемы характерны для распределенных очередей сообщений, почему они случаются и как с ними справиться. Разбираемся со сбоями, ошибками и перегрузками на примере Apache Kafka и RabbitMQ.
Проблемы с распределенными очередями и главные причины их появления
Хотя Apache Kafka — это целая экосистема со множеством компонентов для потоковой передачи событий, ее часто рассматривают в более узком контексте как распределенную очередь сообщений для асинхронного обмена данными между несколькими приложениями. Распределенный характер очереди сообщений предполагает разделение сообщений по нескольким серверам, каждый из которых может обрабатывать часть очереди сообщений и может связываться с другими серверами, чтобы гарантировать обработку всех данных. Примерами таких распределенных очередей являются RabbitMQ, Apache ActiveMQ и Amazon SQS.
В системах с распределенными очередями могут возникнуть следующие проблемы:
- потеря сообщений из-за программных, аппаратных или сетевых сбоев;
- нарушение порядка сообщений, когда они поступают в очередь не в той хронологии, в которой были отправлены;
- ошибки в самих сообщениях, которые не могут быть обработаны приложением-потребителем из-за несовпадения схемы данных, формата, отсутствующих зависимостей или ошибок самого приложения. Такие сообщения могут блокировать обработку других событий в очереди, вызывая сбой всего конвейера обработки данных.
- перегрузка, когда скорость поступления входящих сообщений превышает способность системы их обрабатывать. Это чревато чрезмерному потреблению памяти, снижением производительности и может привести даже к сбою системы.
- высокая задержка обработки данных из-за перегрузки сети, длительного времени обработки и больших размеров сообщений.
Как эти проблемы решаются в Apache Kafka и RabbitMQ, рассмотрим далее. Про ключевые отличия этих систем мы писали здесь.
Перегрузка очереди и ошибки в сообщениях
Решить проблему с перегрузкой очереди можно, ограничив ее способность принимать сообщения, когда их становится слишком много или они поступают очень быстро. В Apache Kafka это реализуется через настройку конфигураций продюсера batch.size и linger.ms, о чем мы подробно писали здесь. В RabbitMQ, который, в отличие от Apache Kafka, сам доставляет сообщения приложениям-потребителям, включается механизм обратного давления на TCP-соединение, когда приложение-продюсер отправляет в очередь слишком много сообщений. Чтобы повысить пропускную способность системы с очередью в RabbitMQ рекомендуется разделить соединения для продюсеров и потребителей. При использовании одного и того же TCP-подключения, сервер может не получить подтверждение сообщения от клиента, что повлияет на производительность потребления. При более низкой скорости потребления сервер будет перегружен.
Также избавиться от перегрузки можно, используя несколько очередей, чтобы обрабатывать их параллельно. В Kafka это реализуется разделением топика на несколько разделов, а в RabbitMQ с помощью обменника типа Fanout, который распараллеливает принятые сообщения в несколько очередей.
Чтобы избежать потери данных без остановки всего конвейера, для сообщений которые не могут быть обработаны приложением-потребителем, можно использовать очередь недоставленных сообщений (Dead Letter Queue, DLQ), о чем мы подробно писали здесь и здесь.
Также проблему с перегрузкой очереди может исправить внедрение механизма повторных попыток для некорректных сообщений, чтобы снизить их количество в DLQ-очередях и повысить общую производительность системы. Про управляемые попытки повторной отправки сообщений в Kafka мы рассказывали в этом материале. В RabbitMQ для этого есть метод basic.reject(), который позволяет клиентам отклонять отдельные доставленные сообщения, предписывая брокеру отбросить их или повторно поставить в очередь. Поскольку basic.reject() не поддерживает массовое отрицательное подтверждение сообщений, RabbitMQ также поддерживает метод basic.nack(), который предоставляет все функции basic.reject, а также позволяет выполнять массовую обработку сообщений.
Что касается большого объема данных, Apache Kafka не предусматривает работу с сообщениями большого размера, по умолчанию ограничивая их размер 1 МБ. Поэтому рекомендуется использовать сжатие и разделение данных на более мелкие фрагменты. В RabbitMQ теоретический предел размера сообщения составляет 2 ГБ, но практически не рекомендуется отправлять в эту систему сообщения размером более 128 МБ. Если же объем публикуемых данных очень велик, вместо очереди сообщений более целесообразно использовать NoSQL-хранилище данных, ориентированное на большие объемы, например, Apache HBase.
Потери сообщений и программно-аппаратные сбои
Чтобы исключить потерю сообщений, в Apache Kafka есть механизм подтверждения acks (acknowledges), который возвращает приложению-продюсеру данные о том, что лидер раздела не только успешно опубликовал сообщение в топике, но и распространил реплики по всем подписчикам. Только после этого сообщение считается успешно записанным. Этот параметр контролирует долговечность отправляемых записей и гарантирует надежность системы, но увеличивает нагрузку на сеть и снижает общую пропускную способность системы.
В RabbitMQ тоже есть механизмы подтверждения и репликации, а также возможность записывать сообщения на диск вместо хранения в оперативной памяти. Для этого при создании очереди ей следует установить тип Durable вместо Transient. Это гарантирует, что сообщения не будут потеряны при перезапуске брокера. В Apache Kafka подобной конфигурации нет, поскольку все сообщения всегда записываются на жесткий диск и хранятся на нем весь период времени, заданный политикой очистки топика, о чем мы писали здесь и здесь.
Задержка обработки данных в Kafka и RabbitMQ
При росте задержки обработки данных следует, прежде всего, проверить пропускную способность сети. Оптимизация сетевого взаимодействия, например использование более быстрых протоколов или уменьшение объема передаваемых данных позволяет сократить время доставки сообщений, что в целом снижает задержку их обработки. Можно использовать кэш или резидентную очередь сообщений. Например, как уже было отмечено выше, в RabbitMQ можно при создании очереди установить ей тип Transient вместо Durable, чтобы принимаемые сообщения хранились в оперативной памяти и быстрее передавались приложению-потребителю.
В Apache Kafka, которая записывает все сообщения на диск, это невозможно. Но архитектура этой платформы потоковой передачи событий спроектирована так, чтобы быстро перемещать данные. Это достигается благодаря последовательным операциям ввода-вывода со структурой Append-Only-Log, которая добавляет новые данные в конец файла, и принципу Read with Zero Copy при перемещении большого количества страниц между диском и сетью с использованием прямого доступа сетевой карты к памяти без нагрузки на ЦП. От чего еще зависит производительность Kafka, и как ее ускорить, мы писали здесь.
Неупорядоченная обработка сообщений
Apache Kafka и RabbitMQ изначально придерживаются принципа FIFO, помещая сообщения в очереди по мере их поступления. В частности, Kafka использует систему хранения на основе журналов, назначая смещение каждому сообщению. Это позволяет приложениям-потребителям считывать данные сообщения в том порядке, в котором они были записаны в журнал.
В RabbitMQ упорядоченность обработки событий гарантируется протоколом AMQP: сообщения, опубликованные в одном канале, проходящие через один обменник, одну очередь и один исходящий канал, будут получены в том же порядке, в котором они были отправлены. С точки зрения очереди сообщения в ней всегда хранятся в порядке их публикации.
В других системах распределенных очередей для упорядочивания обработки сообщений можно добавлять временную метку к каждому сообщению, чтобы сортировать их по этой отметке и обрабатывать в порядке отправки. Аналогично можно присваивать каждому сообщению уникальный идентификатор, чтобы сортировать данные.
Освойте администрирование и эксплуатацию Apache Kafka для потоковой аналитики больших данных на специализированных курсах в нашем лицензированном учебном центре обучения и повышения квалификации для разработчиков, менеджеров, архитекторов, инженеров, администраторов, Data Scientist’ов и аналитиков Big Data в Москве:
- Администрирование кластера Kafka
- Apache Kafka для инженеров данных
- Администрирование Arenadata Streaming Kafka
Источники