NodeJS Express — отправлять определенные маршруты определенным работникам кластера?

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

  • API Server with express, master process
    • instance 1: GET /instances/1/*
    • экземпляр 2: ПОЛУЧИТЬ /экземпляры/2/*

Каждый экземпляр представляет собой отдельный рабочий процесс, и я надеялся, что смогу делегировать все запросы API для конкретного рабочего процесса непосредственно этому рабочему процессу (для выполнения функций в этом рабочем процессе).

instance/:id действительно представляет WorkerID.

Клиент может запросить журналы, где workerID = x, поэтому GET /instances/x/logs.

Цель здесь состоит в том, чтобы мастер направлял все запросы экземпляра X к подпроцессу, обозначенному как x.

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

Каждый из моих рабочих может выполнять вариант длительной задачи (дни, недели, месяцы). Методы являются общими для всех рабочих процессов, но если я вызываю /instances/x/logs, я хочу запросить это только для этого конкретного рабочего процесса. Это цель, которую я ищу, чтобы понять.

// route these to subprocess x
GET /instances/x/logs
POST /instances/x/settings

// route these to subprocess y
GET /instances/y/logs
POST /instances/y/settings

// route these to subprocess z
GET /instances/z/logs
POST /instances/z/settings

// make a new worker process, returns worker ID as reference
POST /instances/

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


person Tiago    schedule 12.10.2018    source источник


Ответы (1)


Каждый экземпляр представляет собой отдельный рабочий процесс, и я надеялся, что смогу делегировать все запросы API для конкретного рабочего процесса непосредственно этому рабочему процессу (для выполнения функций в этом рабочем процессе).

На самом деле вы можете это сделать, но если ваш instance/:id не представляет WorkerID, вы попали в конец.

Предположим, что в следующем примере :id не является рабочим идентификатором:

W – Рабочий

W1/instances/1/:method — имеет следующие методы names, cities, cars

W2/instances/2/:method — имеет следующие методы names, fruits, stats

HTTP-клиент захочет получить доступ:

  1. GET /instances/1/name, отлично, name существует в обоих путях. - ВЕРНО
  2. GET /instances/2/fruits, отлично, fruits существует в этом пути на W2, НО если балансировщик обслуживает вас W1 с этим маршрутом, у вас будет ошибка , так как fruits не существует на W1 - FALSE

Окончательный ответ:

Вы не можете просить рабочих всплывать и служить вашей воле, лучшее, что вы можете сделать, это некоторая связь между мастером и рабочими или иметь некоторые методы, требующие некоторой обработки, и в зависимости от использования ЦП запускать эти методы, когда обслуживается низкий рабочий. Но взгляните на хорошую часть: если они умрут, вы сможете fork создать новые без сбоя всего приложения.

person darklightcode    schedule 12.10.2018
comment
instance/:id действительно представляет WorkerID. Клиент может запросить журналы, где workerID = x, поэтому GET /instance/x/logs. Цель здесь состоит в том, чтобы мастер направлял все запросы экземпляра X к подпроцессу, обозначенному как WX. Ваш сценарий работает для распределения нагрузки между рабочими, которые по сути являются клонами/зеркалами. Каждый из моих рабочих может выполнять вариант длительной задачи (дни, недели, месяцы). Методы являются общими для всех рабочих процессов, но если я вызываю /instance/x/logs, я хочу запросить это только для этого конкретного рабочего процесса. Это цель, которую я ищу, чтобы понять. - person Tiago; 12.10.2018
comment
Надеюсь, расширил мой вопрос для ясности! У вас есть какие-нибудь идеи по этому поводу? В крайнем случае, как я думал, было выставление выделенного сервера REST и сервера веб-сокетов на каждом рабочем, а также обеспечение того, чтобы родительский процесс знал уникальный порт и IP каждого рабочего. Интересно, не слишком ли это. - person Tiago; 12.10.2018
comment
Выставляйте рабочие идентификаторы в виде заголовков! res.setHeader('Worker-ID', cluster.worker.id) . Я думаю, вы даже можете установить их в process.env или какой-то глобальный. Я сделал что-то подобное пару лет назад и использовал WID в заголовках. - person darklightcode; 12.10.2018
comment
И это становится еще лучше с заголовками, потому что вы можете удалить :id из своего URL, новая ссылка будет просто /instances/logs. Одним сегментом меньше, одним беспокойством меньше. Например, я отказался от идеи воркеров в небольших приложениях, потому что каждый созданный воркер потребляет около 9-10 МБ памяти. - person darklightcode; 12.10.2018
comment
Хотя мне все еще нужны вещи, чтобы работать как рабочие. Один рабочий может полностью использовать процессор на этом ядре. Я не возражаю против задержки до тех пор, пока рабочие не закончатся в этом потоке, но я не хочу, чтобы это повлияло на какую-либо другую логику других рабочих. Что касается вашего предложения setHeader, как бы я перенаправил запрос работнику? Я думал, что несколько экспресс-экземпляров, прослушивающих один и тот же порт, просто означают автоматическую балансировку нагрузки - я не могу контролировать, какой работник будет пытаться обработать этот маршрут/запрос, или я неправильно понял? - person Tiago; 12.10.2018
comment
Я видел это для того, что выглядит как необработанное TCP-соединение, любопытно, есть ли что-то подобное для рабочих. Итак, я знаю, что идентификатор рабочего процесса x — это рабочий процесс с идентификатором процесса y, поэтому я нахожу этого рабочего процесса в своей памяти рабочих процессов и делаю его обработчиком этого экспресс-маршрута (поскольку он находится в /instances/x/...): stackoverflow.com/questions/31339915/ - person Tiago; 12.10.2018
comment
В Node.JS 10 есть экспериментальный модуль, nodejs.org/api/worker_threads.html . не пробовал, все еще использую 8. А еще есть этот пакет npm npmjs.com/package/ крошечный рабочий - person darklightcode; 12.10.2018