В наши дни серверные части приложений становятся сложными, и есть много движущихся частей, которые общаются друг с другом через сеть. Существует большая разница между отправкой нескольких байтов от 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
В следующем году я собираюсь начать серию описаний проблем построения распределенных бэкендов.