Основные принципы

Это руководство охватывает основные концепции любого Moleculer приложения.

Сервис

Сервис является простым JavaScript-модулем, содержащим часть сложного приложения. Он изолирован и самодостаточен, это означает, что даже если он отключится или упадёт, остальные сервисы не будут задеты.

Узел

Узел - это просто процесс в ОС, работающий в локальной или внешней сети. Один экземпляр узла может хостить один или несколько сервисов.

Локальный сервис

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

Удалённый сервис

Сервисы, распределённые по нескольким узлам, считаются удалёнными. В этом случае общение между ними осуществляется с помощью транспорта.

Сервис брокер

Сервис брокер является сердцем Moleculer. Он отвечает за управление и связью между службами (локальными и удалёнными). Каждый узел должен иметь экземпляр Сервис брокера.

Транспорт

Транспорт это коммуникационная шина, которая обеспечивает обмен сообщениями. Она передает события, запросы и ответы.

Шлюз

API шлюз предоставляет услуги Moleculer конечным пользователям. Шлюз является обычным Moleculer сервисом, в котором запущен (HTTP, WebSockets и др.) сервер. Он обрабатывает входящие запросы, превращает их в вызовы сервисов, а затем возвращает соответствующие ответы.

Общий вид

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

Архитектура

С точки зрения архитектуры, интернет-магазин можно представить из 2 независимых сервисов: сервиса товаров и сервиса шлюза. Первый отвечает за хранение и управление товарами, а второй просто получает запросы от пользователя и передает их сервису товаров.

Теперь давайте рассмотрим, как этот гипотетический магазин можно создать с Moleculer.

Чтобы убедиться, что наша система устойчиво к сбоям, мы запустим товары и шлюз на отдельных узлах (node-1 и node-2). Если вы помните, то запуск сервисов на отдельных узлах означает, что необходим модуль транспорта для связи между ними. Большинство транспортов, поддерживаемых Moleculer, полагаются на брокера сообщений для межсетевой связи, поэтому нам нужен один из них. В целом внутренняя архитектура нашего магазина представлена на рисунке ниже.

Теперь, при условии, что наши сервисы запущены, интернет-магазин может обрабатывать запросы пользователей. Так давайте посмотрим, что происходит на самом деле при попытке вывести список всех доступных товаров. Сначала запрос (GET /products) получит HTTP-сервер, работающий на узле node-1. Входящий запрос передается с HTTP-сервера на сервис шлюза, который выполняет всю обработку и сопоставление. В этом случае запрос пользователя преобразуется в действие listProducts сервиса products. Далее запрос попадёт в брокер, который проверит, является ли сервис products локальным или удалённым. В данном случае служба products удаленная, поэтому брокер должен использовать модуль транспорта для доставки запроса. Транспорт получит запрос и отправит его в шину сообщений. Поскольку оба узла (node-1 и node-2) подключены к одной и той же шине связи (брокеру сообщений), запрос будет успешно доставлен к узлу node-2. При приеме брокер узла node-2 разберёт входящий запрос и переправит его в сервис products. Наконец, сервис products выполнит действие listProducts и вернёт список всех доступных товаров. Ответ будет отправлен конечному пользователю.

Обработка запросов пользователей

Описание архитектуры

Все детали, которые мы только что увидели, могут показаться пугающими и сложными, но вам не нужно бояться. Moleculer делает все тяжелые приёмы за Вас! Вам (разработчику) нужно сосредоточиться только на логике приложения. Посмотрите на реализацию нашего интернет-магазина.

Реализация

Теперь, когда мы определили архитектуру нашего магазина, давайте его сделаем. Мы будем использовать NATS, систему обмена сообщениями с открытым исходным кодом, в качестве шины для коммуникаций. So go ahead and get the latest version of NATS Server. Запустите с настройками по умолчанию. Вы должны получить следующее сообщение:

[18141] 2016/10/31 13:13:40.732616 [INF] Starting nats-server version 0.9.4
[18141] 2016/10/31 13:13:40.732704 [INF] Listening for client connections on 0.0.0.0:4222
[18141] 2016/10/31 13:13:40.732967 [INF] Server is ready

Далее, создайте новый каталог для нашего приложения, создайте новый package.json и установите зависимости. Мы собираемся использовать moleculer для создания наших сервисов, moleculer-web для HTTP шлюза и nats для коммуникации между ними. В конце концов, ваш package.json должен выглядеть так:

// package.json
{
"name": "moleculer-store",
"dependencies": {
"moleculer": "^0.14.0",
"moleculer-web": "^0.9.0",
"nats": "^1.3.2"
}
}

Наконец, нам нужно настроить брокеров и создать наши сервисы. Давайте создадим новый файл (index.js) и сделаем это:

// index.js
const { ServiceBroker } = require("moleculer");
const HTTPServer = require("moleculer-web");

// создание брокера для первого узла
// определение nodeID и транспорта
const brokerNode1 = new ServiceBroker({
nodeID: "node-1",
transporter: "NATS"
});

// создать сервис "шлюз"
brokerNode1.createService({
// имя сервиса
name: "gateway",
// загрузить HTTP сервер
mixins: [HTTPServer],

settings: {
routes: [
{
aliases: {
// при получении запроса "GET /products" будет выполнено действие "listProducts" из сервиса "products"
"GET /products": "products.listProducts"
}
}
]
}
});

// создание брокера для второго узла
// определение nodeID и транспорта
const brokerNode2 = new ServiceBroker({
nodeID: "node-2",
transporter: "NATS"
});

// создание сервиса "products"
brokerNode2.createService({
// имя сервиса
name: "products",

actions: {
// определение действия, которое вернёт список доступных товаров
listProducts(ctx) {
return [
{ name: "Apples", price: 5 },
{ name: "Oranges", price: 3 },
{ name: "Bananas", price: 2 }
];
}
}
});

// запуск обоих брокеров
Promise.all([brokerNode1.start(), brokerNode2.start()]);

Теперь запустите node index.js в терминале и откройте ссылку http://localhost:3000/products. Вы должны получить следующий ответ:

[
{ "name": "Apples", "price": 5 },
{ "name": "Oranges", "price": 3 },
{ "name": "Bananas", "price": 2 }
]

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

Загляните в раздел Документация для получения более подробной информации или посмотрите страницу Примеры для более комплексных примеров.