Node.js на многоядерных машинах - PullRequest
562 голосов
/ 05 марта 2010

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

Как Node.js вписывается в эту картину?Это его идея как-то распределить несколько экземпляров или как?

Ответы [ 15 ]

670 голосов
/ 31 декабря 2011

[ Эта публикация актуальна по состоянию на 2012-09-02 (новее, чем указано выше). ]

Node.js абсолютно масштабируется на многоядерных машинах.

Да, Node.js - один поток на процесс.Это очень обдуманное проектное решение, устраняющее необходимость иметь дело с семантикой блокировки.Если вы не согласны с этим, вы, вероятно, еще не понимаете, насколько безумно сложно отлаживать многопоточный код.Для более глубокого объяснения модели процесса Node.js и почему она работает таким образом (и почему она НИКОГДА не будет поддерживать несколько потоков), прочитайте мой другой пост .

Итак, как мне взятьПреимущество моего 16-ядерного блока?

Два способа:

  • Для больших сложных вычислительных задач, таких как кодирование изображений, Node.js может запускать дочерние процессы или отправлять сообщения дополнительным рабочим процессам.В этом проекте у вас был бы один поток, управляющий потоком событий, а N процессов, выполняющих сложные вычислительные задачи и пережевывающих другие 15 процессоров.
  • Для масштабирования пропускной способности веб-службы вам необходимо запустить несколько Node.js.серверы на одной коробке, по одному на ядро ​​и распределенный трафик запросов между ними.Это обеспечивает отличную привязку к процессору и масштабирует пропускную способность почти линейно с количеством ядер.

Масштабирование пропускной способности веб-службы

Начиная с версии 6.0.X Node.js модуль кластера прямо из коробки, что упрощает настройку нескольких рабочих узлов, которые могут прослушивать один порт.Обратите внимание, что это НЕ то же самое, что более старый модуль кластера Learnboost, доступный через npm .

if (cluster.isMaster) {
  // Fork workers.
  for (var i = 0; i < numCPUs; i++) {
    cluster.fork();
  }
} else {
  http.Server(function(req, res) { ... }).listen(8000);
}

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

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

  1. Запустите службу Node.js через веб-прокси, например Nginx или Apache - то, что может регулировать соединение (если вы не хотите перегрузки)условия, чтобы полностью убрать флажок), переписать URL-адреса, предоставить статический контент и прокси-серверы других вспомогательных служб.

  2. Периодически перезапускайте рабочие процессы.В случае продолжительного процесса даже небольшая утечка памяти в конечном итоге приведет к увеличению.

  3. Настройка сбора / мониторинга журналов


PSЕсть обсуждение между Аароном и Кристофером в комментариях к другому посту (на момент написания статьи это самый верхний пост).Несколько комментариев по этому поводу:

  • Модель общего сокета очень удобна для того, чтобы позволить нескольким процессам прослушивать один порт и конкурировать на прием новых соединений.Концептуально, вы могли бы подумать о том, что предварительно разветвленный Apache сделает это со значительным предупреждением, что каждый процесс примет только одно соединение, а затем умрет.Потеря эффективности для Apache приводит к накладным расходам на создание новых процессов и не имеет ничего общего с операциями с сокетами.
  • Для Node.js наличие N работников, конкурирующих на одном сокете, является чрезвычайно разумным решением.Альтернативой является настройка встроенного внешнего интерфейса, такого как Nginx, и передача этого прокси-трафика отдельным работникам, чередуя работников для назначения новых соединений.Два решения имеют очень похожие характеристики производительности.И поскольку, как я упоминал выше, вы, вероятно, захотите, чтобы Nginx (или его альтернатива) в любом случае стоял перед вашим нодовым сервисом, выбор здесь действительно:

Shared Ports: 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) ...}

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

41 голосов
/ 10 марта 2010

Один из методов заключается в том, чтобы запустить несколько экземпляров node.js на сервере, а затем поместить балансировщик нагрузки (предпочтительно неблокирующий, такой как nginx) перед ними.

30 голосов
/ 09 декабря 2010

Райан Даль отвечает на этот вопрос в техническом выступлении, которое он дал в Google прошлым летом.Перефразируя, «просто запустите несколько процессов узлов и используйте что-нибудь разумное, чтобы позволить им общаться. Например, IPC в стиле sendmsg () или традиционный RPC».

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

ОБНОВЛЕНИЕ - 10/11/11 : Похоже, что в сообществе узлов все согласны с тем, что Cluster теперь является предпочтительным модулем для управления несколькими экземплярами узлов на одном компьютере. Навсегда тоже стоит посмотреть.

17 голосов
/ 28 апреля 2014

Вы можете использовать cluster module. Отметьте это .

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);
}
13 голосов
/ 20 июля 2010

Многоузловая система использует все имеющиеся у вас ядра.
Взгляните на http://github.com/kriszyp/multi-node.

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

10 голосов
/ 05 февраля 2015

Как упоминалось выше, Cluster будет масштабировать и распределять нагрузку на ваше приложение по всем ядрам.

добавив что-то вроде

cluster.on('exit', function () {
  cluster.fork();
});

Перезапустит всех неисправных работников.

В наши дни многие люди предпочитают PM2 , который обрабатывает кластеризацию для вас, а также предоставляет некоторые интересные функции мониторинга .

Затем добавьте Nginx или HAProxy перед несколькими машинами, работающими с кластеризацией, и у вас будет несколько уровней отработки отказа и гораздо более высокая нагрузочная способность.

8 голосов
/ 02 октября 2015

Узел 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.
}

проверьте эту статью для полного учебника

7 голосов
/ 08 марта 2011

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

7 голосов
/ 13 марта 2010

Будущая версия узла позволит вам раскошелиться на процесс и передать ему сообщения, и Райан заявил, что хочет найти какой-то способ также обмениваться обработчиками файлов, так что это не будет прямой реализацией Web Worker.

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

5 голосов
/ 03 февраля 2012

Новый ребенок на блоке здесь - LearnBoost's "Up" .

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...