В наши дни серверные части приложений становятся сложными, и есть много движущихся частей, которые общаются друг с другом через сеть. Существует большая разница между отправкой нескольких байтов от A к B и надежным обменом сообщениями️

  • 🙏 Как работать с динамическими компонентами? (т.е. части, которые приходят и / или временно исчезают)
  • 🙏 Как обрабатывать сообщения, которые мы не можем доставить немедленно? (например, ожидая, пока компонент вернется в сеть) Кто хочет потерять важные сообщения?
  • 🙏 Как маршрутизировать сообщения в сложной микросервисной архитектуре? (т.е. один к одному, один ко многим или очень, очень индивидуальный)
  • 🙏 Как мы обрабатываем сетевые ошибки? («A» не может отправить сообщение на «B», так как «B» перезапускается в течение 10 секунд, а «A» терпит неудачу при попытке отправить.

Zeronode был создан на основе zeromq, чтобы решить эти и некоторые другие общие проблемы, с которыми разработчики столкнутся при создании надежных распределенных систем.
С zeronode очень просто создавать сложные межсерверные коммуникации (т. е. строить сетевые топологии).

Основы (npm и zeronode)

Zeronode позволяет создавать сложные сетевые топологии (например, линейную, кольцевую, частичную или полную сетку, звезду, три, гибридную…). Но давайте начнем с основ. Вы хотите отправить сообщение из A в B (💻 → 💻), и это означает, что вам нужно создать 2 узла с Zeronode.

// ** Simple node with zeronode
import Node from 'zeronode';
let node1 = new Node({
  id: 'myAwsomeNode',
  bind: 'tcp://127.0.0.1:6000',
  options: {} // ** let's talk about options later on 
});

Думайте о каждом узле как о субъекте (т. Е. участнике, минимальном строительном блоке) в вашей сетевой системе.

  • 👉 узел может подключаться к нескольким узлам (например, node.connect (addressOfNodeB), node.connect (addressOfnodeC))
  • 👉 узлы могут подключаться к конкретному узлу, если последний привязан к какому-либо интерфейсу (например, node.bind (interfaceAddress))
  • 👉 если узел A подключен к узлу B, то у нас есть канал между ними, и оба узла могут общаться друг с другом
  • 👉 узлы устойчивы к перезапускам, сбоям сети, порядку подключения / привязки 💪🤘
  • 👉 узлы могут работать на одном или разных машинах, процессах, контейнерах и т. Д.
  • 👉Zeronode обеспечивает передачу данных между узлами с помощью шаблонов запрос / ответ и тик (огонь забыл)
  • 👉 Еще несколько суперспособностей для расширенных схем балансировки нагрузки встроены в коробку.

Давайте создадим простой сервер (службу), который позволяет клиентским службам (т.

// ** myServiceServer.js
import Node from 'zeronode';
(async function() {
let myServiceServer = new Node({ 
  id: 'myServiceServer',  
  bind: 'tcp://127.0.0.1:6000', 
  options: { layer: 'LayerA' } 
});
// ** attach event listener to myServiceServer
myServiceServer.onTick('welcome', (data) => {
  console.log('onTick - welcome', data);
});
// ** attach request listener to myServiceServer
myServiceServer.onRequest('welcome', ({ body, reply, next }) => {
  console.log('onRequest - welcome', body);
  reply("Hello client");
});
// ** bind node to given address
await myServiceServer.bind();
}());

Теперь давайте создадим клиента

// ** myServiceClient.js
import Node from 'zeronode'
(async function() {
let myServiceClient = new Node({ options: { layer: 'LayerA' } });
//** connect one node to another node with address
await myServiceClient.connect('tcp://127.0.0.1:6000');
let serverNodeId = 'myServiceServer';
// ** tick() is like firing an event to another node
myServiceClient.tick({ 
  to: serverNodeId, 
  event: 'welcome', 
  data:'Hi server!!!' 
});
// ** request is a promise which will be resolve after reply.
let responseFromServer = await myServiceClient.request({ 
  to: serverNodeId,  
  event: 'welcome', 
  data: 'Hi server, I am client !!!' 
});
console.log(`response from server is "${responseFromServer}"`);
// response from server is "Hello client."
}());

Теперь мы знаем основы :)

Более 1 млн игроков в разработке

Zeronode был построен не для простой отправки сообщения от одного сервиса к другому (это можно было сделать сотнями других способов с сотнями пакетов также) . Продвинутые шаблоны балансировки нагрузки и приятный API - не единственная сильная сторона zeronode, но у него есть настоящий волшебный соус внутри.

А вот 2 из них

Магия 1:

  • Создайте узлы A (сервер) и B (клиент) с нулевым узлом и подключите B к A, как в примере выше.
  • Теперь вы можете отправлять сообщения от A к B и от B к A. Давайте отправлять сообщения от B к A с помощью setTimeout (someSenderFunction, 1000)
  • Теперь выключите / завершите процесс A, а затем через некоторое время (например, 20 секунд) переключите его обратно.

Вы увидите, что все сообщения отправляются в A.

Магия 2:

A и B устойчивы к перезапуску обеих служб, и вам не нужно изобретать и внедрять этот «механизм переподключения» снова и снова (например, в случае, если вы знаете, как это сделать действительно правильным образом). Итак, что это означает? вам не нужно включать их в определенном порядке. (да, A действует как сервер, но вы можете просто создать B, отправить сообщения A, а затем создать / переключиться на сервер A).

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

Это всего лишь 2 файла cookie внутри zeronode, но у нас их больше, и я постараюсь рассказать о них в своих следующих публикациях.

P.S

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