Kafka VS RabbitMQ

Vasiliy Ozerov
5 min readDec 27, 2018

--

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

Самыми популярными продуктами в этой области являются kafka и rabbitmq. Да, конечно, в голову еще может прийти activemq или nats, но в реальности я видел только один проект, который бы использовал одно из этих решений.

Давайте все же разберемся чем отличаются эти системы и когда какую использовать.

Основная мысль.

Kafka — простой как бревно брокер, который позволяет вам очень быстро сохранять сообщения. Единственная задача кафки при приеме сообщения сохранить его на диск. Все.

Отсюда следует один простой вывод — всю логику по работе с сообщениями вам придется реализовывать на клиенте. Даже сохранять место откуда начинать читать сообщения в следующий раз (лукавлю — тут оно сохраняется в специальном offsets топике клиентом).

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

А еще кафка очень хорошо масштабируется горизонтально. Просто добавляем ноду и ребалансим partitions на все ноды — все.

Rabbitmq. Как говорит нам официальный сайт — самая популярная система для организации очередей. Реббит уже не так прост — тут вам и exchanges с роутингом, и куча плагинов для delayed messages, deadletter и прочего хлама. За сообщениями следит сам кролик. Как только консьюмер подтвердил обработку сообщения оно удаляется. Если консьюмер отвалился посередине — реббит вернет сообщение в очередь. В общем хороший комбайн, когда нужно перекидывать сообщения между сервисами. Цена этого — производительность.

Реббит пытается сделать очень многое, что естественным образом влечет за собой потребление ресурсов.

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

Быстрое сравнение kafka vs rabbitmq.

Для тестов я написал очень простое приложение на Golang, которое принимает сообщения в json формате по http и складывает их либо в Кафку, либо в rabbitmq (https://github.com/vozerov/kafka-vs-rabbitmq/tree/master/app).

Схема простая — app сервер — там запущен наш сервис, который слушает 80 порт. Да, даже без nginx. За ним стоят два сервера либо кафки либо реббита. Для кафки на тех же хостах запущен zookeeper.

Дальше берем в руки loader.io с бесплатными тестам, загоняем туда 1,5 kb json’ку и фигачим 10 000 сообщений в секунду на наше golang приложение. Считаем кол-во ошибок, среднее время ответа и тд.

3 машинки (app / и две ноды под реббит/кафку) подняты на DigitalOcean в Амстердаме, за 20$ / month каждая. 2 CPU, 4 GB RAM, 80 GB SSD. Очень простые машинки для 10 000 rps. Суммарная стоимость решения — 60$/month. Да, конечно, сюда можно добавить наворотов типа load balancer’а с терменированием ssl, но для теста нам этого не нужно. Тестируем же message broker’ы, а не Nginx, верно?

Тест 1. Kafka. 10 000 RPS. Wait For All. Sync Producer.

Как видим — у нас очень стабильное время ответа (182ms), даже если учесть что loader.io запускает тесты в амазоне в Америке, а наши машинки находятся в Европе.

Ну и отсутствие ошибок конечно радует.

Первоначальный пик связан с установлением соединения с кафкой нашим сервисом.

Самый главный момент в этом тесте — это то, что producer сообщений синхронный и он дожидается записи на все реплики (config.Producer.RequiredAcks = sarama.WaitForAll). То есть мы точно ответив клиенту 200 уже никак не потеряем его сообщение.

И еще один график с внутреннего мониторинга Кафки:

Пытливый читатель может заметить, что сетевая загрузка отличается от того что написал loader.io (1 gb / 1 min ~ 16 mb/sec) — это связано с тем, что наш сервис отправляет сообщения в кафку в сжатом виде.

И последнее — данная схема очень красиво масштабируется горизонтально на всех уровнях. Докидываем ноды сервиса, докидываем ноды кафки и вуаля — мы уже готовы принимать 500 000 сообщений в секунду. А чтобы снизить задержки — развернем несколько инсталляций go app + kafka в разных гео и зароутим через cloudflare load balancers.

Тест 2. RabbitMQ. 10 000 RPS. High Available Cluster. ASync Producer.

С реббитом на таких нагрузках все немного хуже. Во-первых немного про настройку кластера. Тут все просто — две машинки в одном кластере, полностью синхронизируют очередь в которую пишет клиент. Настраивалось все по оф гайдам — https://www.rabbitmq.com/ha.html.

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

С другой стороны — в HA режиме на таких скромных сервачках реббит вытягивает до 4k/sec.

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

Тест 3. RabbitMQ. 10 000 RPS. Single Node. ASync Producer.

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

В принципе все логично — время ответов уменьшилось до 1,5 секунды, что не может не радовать. Да и кол-во сообщений в секунду дотягивает до уровня кафки:

Выводы и полезные ссылки.

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

Ну а чисто по моему субъективному мнению, если вам надо быстро принять десятки / сотни тысяч сообщений в секунду — вам стопудово стоит выбрать кафку. Особенно за 60$/month для 10 000 сообщений в секунду. Потом скажите спасибо.

--

--