Node.js на многоядерных машинах
Node.js выглядит интересно, НО я должен что-то упустить - разве Node.js не настроен только на запуск одного процесса и потока?
Тогда как это масштабируется для многоядерных процессоров и серверов с несколькими процессорами? В конце концов, это все замечательно - это сделать как можно быстрее однопоточный сервер, но для высоких нагрузок я бы хотел использовать несколько процессоров. То же самое касается ускорения работы приложений - сегодня кажется, что путь заключается в использовании нескольких процессоров и распараллеливании задач.
Как Node.js вписывается в эту картину? Его идея как-то распространять несколько экземпляров или как?
17 ответов
[Это сообщение является актуальным по состоянию на 2012-09-02 (новее, чем указано выше).]
Node.js действительно масштабируется на многоядерных машинах.
Да, Node.js - один поток на процесс. Это очень продуманное проектное решение, устраняющее необходимость иметь дело с семантикой блокировки. Если вы не согласны с этим, вы, вероятно, еще не понимаете, насколько безумно сложно отлаживать многопоточный код. Для более глубокого объяснения модели процесса Node.js и почему она работает таким образом (и почему она НИКОГДА не будет поддерживать несколько потоков), прочитайте мой другой пост.
Итак, как мне воспользоваться преимуществами моего 16-ядерного блока?
Два пути:
- Для больших сложных вычислительных задач, таких как кодирование изображений, Node.js может запускать дочерние процессы или отправлять сообщения дополнительным рабочим процессам. В этом проекте у вас был бы один поток, управляющий потоком событий, а N процессов, выполняющих сложные вычислительные задачи и пережевывающих остальные 15 процессоров.
- Для масштабирования пропускной способности на веб-сервисе вы должны запустить несколько серверов Node.js на одном компьютере, по одному на ядро, и разделить трафик между ними. Это обеспечивает отличную привязку к процессору и масштабирует пропускную способность почти линейно с количеством ядер.
Масштабирование пропускной способности на веб-сервисе
Начиная с версии 6.0.X Node.js включает модуль кластера прямо из коробки, что упрощает настройку нескольких рабочих узлов, которые могут прослушивать один порт. Обратите внимание, что это НЕ то же самое, что более старый модуль "cluster" learnboost, доступный через npm.
if (cluster.isMaster) {
// Fork workers.
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
} else {
http.Server(function(req, res) { ... }).listen(8000);
}
Рабочие будут бороться за принятие новых подключений, и, скорее всего, победит наименее загруженный процесс. Он работает довольно хорошо и может увеличить пропускную способность на многоядерном процессоре.
Если у вас достаточно нагрузки, чтобы позаботиться о нескольких ядрах, вы захотите сделать еще несколько вещей:
Запустите службу Node.js за веб-прокси, таким как Nginx или Apache - что может привести к удушению соединения (если только вы не хотите, чтобы условия перегрузки приводили к полному отключению), переписать URL-адреса, обслуживать статический контент и прокси-сервер других вспомогательных служб.
Периодически перерабатывайте ваши рабочие процессы. Для длительного процесса даже небольшая утечка памяти в конечном итоге приведет к увеличению.
Настройка сбора / мониторинга журналов
PS: есть обсуждение между Аароном и Кристофером в комментариях к другому посту (на момент написания статьи это самый верхний пост). Несколько комментариев по этому поводу:
- Модель с общими сокетами очень удобна, поскольку позволяет нескольким процессам прослушивать один порт и конкурировать за новые подключения. Концептуально, вы могли бы подумать о том, что предварительно разветвленный Apache сделает это со значительным предупреждением, что каждый процесс примет только одно соединение, а затем умрет. Потеря эффективности для Apache приводит к накладным расходам на создание новых процессов и не имеет ничего общего с операциями с сокетами.
- Для Node.js наличие N работников, конкурирующих в одном сокете, является чрезвычайно разумным решением. Альтернативой является настройка встроенного внешнего интерфейса, такого как Nginx, и передача этого прокси-трафика отдельным работникам, чередуя работников для назначения новых соединений. Два решения имеют очень похожие характеристики производительности. И поскольку, как я упоминал выше, вы, вероятно, захотите, чтобы Nginx (или альтернативный вариант) в любом случае стоял перед вашим сервисом узлов, выбор здесь действительно один:
Общие порты: nginx (port 80) --> Node_workers x N (sharing port 3000 w/ Cluster)
против
Индивидуальные порты: nginx (port 80) --> {Node_worker (port 3000), Node_worker (port 3001), Node_worker (port 3002), Node_worker (port 3003) ...}
Возможно, есть некоторые преимущества в настройке отдельных портов (возможно меньшая связь между процессами, более сложные решения по балансировке нагрузки и т. Д.), Но это определенно больше работы для настройки, а встроенный модуль кластера невелик -сложная альтернатива, которая работает для большинства людей.
Одним из методов может быть запуск нескольких экземпляров node.js на сервере, а затем установка балансировщика нагрузки (предпочтительно неблокирующего, такого как nginx) перед ними.
Райан Даль отвечает на этот вопрос в техническом докладе, который он дал в Google прошлым летом. Перефразируя, "просто запустите процессы с несколькими узлами и используйте что-нибудь разумное, чтобы позволить им обмениваться данными. Например, IPC в стиле sendmsg () или традиционный RPC".
Если вы хотите испачкать руки, проверьте модуль spark2 Forever.Это упрощает порождение процессов с несколькими узлами. Он управляет настройкой общего доступа к портам, поэтому каждый из них может принимать подключения к одному и тому же порту, а также автоматически перезапускаться, если вы хотите убедиться, что процесс перезапускается, если / когда он умирает.
ОБНОВЛЕНИЕ - 10/11/11: Похоже, что в сообществе узлов все считают, что кластер является предпочтительным модулем для управления несколькими экземплярами узлов на одном компьютере. Навсегда тоже стоит посмотреть.
Вы можете использовать кластерный модуль. Проверьте это.
var cluster = require('cluster');
var http = require('http');
var numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
// Fork workers.
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', function(worker, code, signal) {
console.log('worker ' + worker.process.pid + ' died');
});
} else {
// Workers can share any TCP connection
// In this case its a HTTP server
http.createServer(function(req, res) {
res.writeHead(200);
res.end("hello world\n");
}).listen(8000);
}
Node Js поддерживает кластеризацию, чтобы использовать все преимущества вашего процессора. Если вы не используете его с кластером, то, вероятно, вы тратите впустую свои аппаратные возможности.
Кластеризация в Node.js позволяет создавать отдельные процессы, которые могут использовать один и тот же порт сервера. Например, если мы запустим один HTTP-сервер на порту 3000, это будет один сервер, работающий в одном потоке на одном ядре процессора.
Код, показанный ниже, позволяет кластеризовать ваше приложение. Этот код является официальным кодом, представленным Node.js.
var cluster = require('cluster');
var numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
// Fork workers.
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
Object.keys(cluster.workers).forEach(function(id) {
console.log("I am running with ID : " + cluster.workers[id].process.pid);
});
cluster.on('exit', function(worker, code, signal) {
console.log('worker ' + worker.process.pid + ' died');
});
} else {
//Do further processing.
}
проверьте эту статью для полного урока
Многоузловая система использует все имеющиеся у вас ядра.
Посмотрите на http://github.com/kriszyp/multi-node.
Для более простых нужд вы можете запустить несколько копий узла на разных номерах портов и поставить балансировщик нагрузки перед ними.
Как упоминалось выше, Cluster будет масштабировать и распределять нагрузку на ваше приложение по всем ядрам.
добавив что-то вроде
cluster.on('exit', function () {
cluster.fork();
});
Перезапустит любых провальных работников.
В наши дни многие люди также предпочитают PM2, который обрабатывает кластеризацию для вас, а также предоставляет некоторые интересные функции мониторинга.
Затем добавьте Nginx или HAProxy перед несколькими компьютерами, работающими с кластеризацией, и у вас будет несколько уровней отработки отказа и гораздо более высокая нагрузочная способность.
Будущая версия узла позволит вам раскошелиться на процесс и передать ему сообщения, и Райан заявил, что хочет найти какой-то способ обмена файловыми обработчиками, так что это не будет прямой реализацией Web Worker.
В настоящее время для этого нет простого решения, но оно все еще очень рано, и node - один из самых динамичных проектов с открытым исходным кодом, которые я когда-либо видел, поэтому ожидайте чего-то удивительного в ближайшем будущем.
Вы можете запустить ваше приложение node.js на нескольких ядрах, используя модуль кластера в сочетании с модулем os, который можно использовать для определения того, сколько у вас процессоров.
Например, давайте представим, что у вас есть server
модуль, который запускает простой http-сервер на сервере, и вы хотите запустить его для нескольких процессоров:
// Dependencies.
const server = require('./lib/server'); // This is our custom server module.
const cluster = require('cluster');
const os = require('os');
// If we're on the master thread start the forks.
if (cluster.isMaster) {
// Fork the process.
for (let i = 0; i < os.cpus().length; i++) {
cluster.fork();
}
} else {
// If we're not on the master thread start the server.
server.init();
}
Spark2 основан на Spark, который больше не поддерживается. Кластер является его преемником, и у него есть несколько интересных функций, таких как создание одного рабочего процесса на ядро процессора и восстановление мертвых рабочих.
Я должен добавить важное различие между использованием сборки узла в режиме кластера и диспетчера процессов, такого как режим кластера PM2.
PM2 обеспечивает перезагрузку с нулевым временем простоя, когда вы работаете.
pm2 start app.js -i 2 --wait-ready
В свои коды добавьте следующее
process.send('ready');
Когда ты звонишь
pm2 reload app
после обновления кода PM2 перезагрузит первый экземпляр приложения, дождется вызова «готов», а затем перейдет к перезагрузке следующего экземпляра, гарантируя, что у вас всегда есть активное приложение для ответа на запросы.
Хотя, если вы используете кластер nodejs, при перезапуске и ожидании готовности сервера будет время простоя.
Я использую Node worker для простого запуска процессов из моего основного процесса. Кажется, работает отлично, пока мы ждем официального пути.
Новый ребенок на блоке здесь - "Up" LearnBoost.
Он обеспечивает "перезагрузки с нулевым временем простоя" и дополнительно создает несколько рабочих (по умолчанию количество процессоров, но оно настраивается), чтобы обеспечить лучшее из всех миров.
Он новый, но, кажется, довольно стабильный, и я успешно использую его в одном из моих текущих проектов.
Я искал приложение Clusterize для всех доступных ядер ЦП и нашел себя здесь. Где я нашел это ключевое слово - это команда Pm2
pm2 примеры
Вот что я нашел
Кластеризируйте приложение для всех доступных ядер ЦП:
$ pm2 start -i max
Если вам нужно установить pm2, используйте эти команды
npm install -g pm2
yan add -g pm2
или
Используйте эту ссылку здесь
Также возможно спроектировать веб-сервис как несколько автономных серверов, которые слушают сокеты Unix, так что вы можете использовать такие функции, как обработка данных, в отдельных процессах.
Это похоже на большинство архитектур веб-серверов scrpting / database, где процесс cgi обрабатывает бизнес-логику, а затем отправляет и извлекает данные через сокет unix в базу данных.
разница в том, что обработка данных записывается как веб-сервер узла, прослушивающий порт.
это более сложно, но в конечном итоге это то, куда должна идти разработка многоядерных систем. многопроцессная архитектура, использующая несколько компонентов для каждого веб-запроса.
Можно масштабировать NodeJS до нескольких блоков, используя чистый балансировщик нагрузки TCP (HAProxy) перед несколькими блоками, запускающими по одному процессу NodeJS каждый.
Если у вас есть общие знания, которыми вы можете поделиться между всеми экземплярами, вы можете использовать центральное хранилище Redis или подобное, к которому можно получить доступ из всех экземпляров процесса (например, из всех блоков)