Обмен сообщениями между сервисами с ZeroMQ и Node.js

ZeroMQ

ZeroMQ это небольшая и шустрая библиотека для обмена сообщениями, которая одинаково хорошо работает как между процессами на одном хосте, так и по сети. Хотя она написана на C++, очень добрые люди создали адаптеры для всего: хоть для Node.js, хоть для Haskell.

Работа с ZeroMQ напоминает работу с TCP/UDP сокетами. Один процесс создаёт сокет и привязывает его к адресу, второй — подключается к первому, и понеслась, родная. Правда, сокеты в ZMQ весьма необычные. Но, наверное, стоит начать с примеров, и по ходу дела уже вдаваться в детали.

В прошлый раз я рассказал про три обычных паттерна работы с очередями сообщений:

  • Отправить-и-забыть
  • Запрос-ответ
  • Publish-subscribe

Почему бы не попробовать сделать их на Node.JS и ZeroMQ?

Установка

Лучше всего описана в официальной документации, но вообще-то в NPM есть пакет  zmq , который нам и нужен. Если в Mac OS он у меня завёлся сразу, то на Debian пришлось сначала устанавливать  libzmq-dev , а потом уже разговаривать с NPM. Таким образом, если вокруг стоит Debian/Ubuntu/половина-образов-Docker, то нужно использовать такое заклинание:

А на маке  npm install ...  должно хватить. Как всегда, когда с установкой становится совсем непонятно, есть документация.

Паттерн «отправить-и-забить»

Оказывается, ZeroMQ в курсе существования паттернов, и идёт с комплектов сокетов, заточенных под работу именно с ними. Например, в ZMQ есть паттерн push-pull, который практически идентичен «отправить-и-забыть», и для него созданы конкретные сокеты PUSH и PULL.

Представим, что в мире Hello-World приложений для полного счастья стало не хватать сервиса, который раз в две секунды отправляет сообщение «Ping #1,2,3..»:

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

И если запустить это счастье:

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

  1. Совсем без разницы, кто запустился первым — клиент или сервер. Сокеты всё равно создадутся, и как только оба сервиса появятся в сети — через мировой эфир полетят сообщения.
  2. Даже если убить сервер, клиент останется жить. Как только сервер вернётся, клиент переподключится автоматически.
  3. Если прибить клиента, то сервер будет накапливать неотправленные сообщения до тех пор, покуда не придёт кто-то, кто их заберёт. Например, тот же клиент.
  4. Можно запустить сразу два клиента, но они тут же начнут соревноваться за сообщения. Первый, например, получит чётные, а второй — нечетные. Или наоборот. Важно то, что у каждого сообщения будет только один получатель.
  5. Если прибить сервер, пока у него есть неотправленные сообщения — они пропадут навсегда. Другими словами, ZeroMQ ни разу не durable.

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

Запрос-ответ

В отличие от предыдущего товарища, этот паттерн подразумевает реакцию на исходящие сообщения. Как и в прошлый раз, у ZMQ есть специальные сокеты для этого: REQ и REP. Итак, сервер идёт первым:

Пример всё еще простой. Клиента я сделал чуть-чуть по-объёмнее, но его логика сводится к «отправь сообщение, получи ответ, повторяй раз в две секунды»:

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

С этим примером тоже полезно поиграть и, например, заметить, что ZeroMQ-сокеты нельзя использовать «не по-паттерну». Например, на одно входящее сообщение REP-сокет может ответить только один раз. Если попытаться вызвать send два раза, то ZMQ припасёт второе сообщение для следующего запроса. Похожие правила распространяются на все сокеты. PUSH сокет может только отправлять, но не может получать, PULL — строго наоборот, и т. д.

Publish-subscribe

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

По традиции, сервер идёт первым:

А за ним — клиент:

Раз в две секунды сервер генерирует сообщение heartbeat, а клиент на него подписывается. Всё просто.

Мораль

Я могу припомнить пару случаев из жизни, когда два удалённых куска приложения должны были общаться друг с другом, и мне приходилось либо страдать с TCP сокетами, либо делать какого-нибудь HTTP клиента. А знал бы тогда ZeroMQ, задача решилась бы мгновенно. Жалко только, что в нём нет bluetooth… Всё становится лучше с bluetooth.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *