Node.js na maszynach wielordzeniowych


605

Node.js wygląda interesująco, ALE muszę coś przeoczyć - czy Node.js nie jest dostrojony tylko do działania na jednym procesie i wątku?

Jak zatem skalować w przypadku procesorów wielordzeniowych i serwerów wieloprocesorowych? W końcu świetnie jest zrobić jak najszybciej serwer jednowątkowy, ale przy dużych obciążeniach chciałbym użyć kilku procesorów. To samo dotyczy przyspieszania aplikacji - wydaje się, że dzisiaj sposób polega na użyciu wielu procesorów i równoległym wykonywaniu zadań.

Jak Node.js pasuje do tego obrazu? Czy jego pomysłem jest jakoś dystrybuowanie wielu instancji czy co?


4
Wygląda na to, że Ryah zaczyna poważnie myśleć o włączeniu wbudowanej obsługi wielordzeniowej w węźle: github.com/joyent/node/commit/…
broofa,

2
Menedżer procesów PM2 używa modułu klastra wewnętrznie do rozprzestrzeniania aplikacji NodeJS na wszystkie dostępne rdzenie: github.com/Unitech/pm2
Unitech

@broofa, To nie są prawdziwe wątki, a procesy potomne nie mają wspólnej pamięci. Zobacz także Jaki jest ekwiwalent Nodejsa dla prawdziwych wątków Java i zmiennych niestabilnych? .
Pacerier

Odpowiedzi:


696

[ Ten post jest aktualny na dzień 2012-09-02 (nowszy niż powyżej). ]

Node.js absolutnie skaluje się na maszynach wielordzeniowych.

Tak, Node.js to jeden wątek na proces. Jest to bardzo celowa decyzja projektowa i eliminuje potrzebę radzenia sobie z semantyką blokowania. Jeśli się z tym nie zgadzasz, prawdopodobnie jeszcze nie zdajesz sobie sprawy z tego, jak niesamowicie trudno jest debugować wielowątkowy kod. Aby uzyskać głębsze wyjaśnienie modelu procesu Node.js i dlaczego działa on w ten sposób (i dlaczego NIGDY nie będzie obsługiwać wielu wątków), przeczytaj mój drugi post .

Jak więc skorzystać z mojego 16-rdzeniowego urządzenia?

Dwie drogi:

  • W przypadku dużych zadań obliczeniowych, takich jak kodowanie obrazu, Node.js może odpalać procesy potomne lub wysyłać wiadomości do dodatkowych procesów roboczych. W tym projekcie miałbyś jeden wątek zarządzający przepływem zdarzeń i procesami N wykonującymi ciężkie zadania obliczeniowe i przełamującymi pozostałe 15 procesorów.
  • Aby skalować przepustowość w usłudze sieciowej, powinieneś uruchomić wiele serwerów Node.js w jednym urządzeniu, po jednym na rdzeń i rozdzielić ruch między nimi. Zapewnia to doskonałe powinowactwo procesora i skaluje przepustowość prawie liniowo wraz z liczbą rdzeni.

Skalowanie przepustowości w serwisie internetowym

Od wersji 6.0.X Node.js dołączono moduł klastra od razu po wyjęciu z pudełka, co ułatwia skonfigurowanie wielu pracowników węzłów, którzy mogą nasłuchiwać na jednym porcie. Zauważ, że NIE jest to to samo, co starszy moduł „klastra” learnboost dostępny przez npm .

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

Pracownicy będą rywalizować o akceptację nowych połączeń, a najmniej obciążony proces najprawdopodobniej wygra. Działa całkiem dobrze i może dość dobrze skalować przepustowość w urządzeniach wielordzeniowych.

Jeśli masz wystarczająco dużo obciążenia, aby zająć się wieloma rdzeniami, będziesz chciał zrobić jeszcze kilka rzeczy:

  1. Uruchom usługę Node.js za web-proxy, takim jak Nginx lub Apache - coś, co może dławić połączenie (chyba że chcesz, aby warunki przeciążenia całkowicie obniżyły pole), przepisz adresy URL, podaj zawartość statyczną i proxy inne pod-usługi.

  2. Okresowo przetwarzaj procesy robocze. W przypadku długotrwałego procesu nawet niewielki wyciek pamięci ostatecznie się zsumuje.

  3. Skonfiguruj zbieranie / monitorowanie dziennika


PS: Dyskusja między Aaronem i Christopherem w komentarzach do innego postu (na początku tego pisma, jest to najwyższy post). Kilka komentarzy na ten temat:

  • Model wspólnego gniazda jest bardzo wygodny, ponieważ pozwala wielu procesom nasłuchiwać na jednym porcie i konkurować o akceptację nowych połączeń. Koncepcyjnie możesz pomyśleć o gotowym Apache, który robi to ze znaczącym zastrzeżeniem, że każdy proces zaakceptuje tylko jedno połączenie, a następnie umrze. Utrata wydajności Apache polega na tworzeniu nowych procesów i nie ma nic wspólnego z operacjami gniazd.
  • Dla Node.js, gdy N pracowników konkuruje na jednym gnieździe, jest niezwykle rozsądnym rozwiązaniem. Alternatywą jest skonfigurowanie front-endu, takiego jak Nginx, i zapewnienie tego ruchu proxy do poszczególnych pracowników, na przemian między pracownikami w celu przypisania nowych połączeń. Te dwa rozwiązania mają bardzo podobną charakterystykę wydajności. A ponieważ, jak wspomniałem powyżej, prawdopodobnie będziesz chciał, aby Nginx (lub alternatywa) przewyższał twoją usługę węzła, wybór tutaj jest naprawdę pomiędzy:

Współużytkowane porty: nginx (port 80) --> Node_workers x N (sharing port 3000 w/ Cluster)

vs

Poszczególne porty: nginx (port 80) --> {Node_worker (port 3000), Node_worker (port 3001), Node_worker (port 3002), Node_worker (port 3003) ...}

Prawdopodobnie istnieją pewne zalety konfiguracji poszczególnych portów (możliwość mniejszego sprzężenia między procesami, bardziej wyrafinowane decyzje dotyczące równoważenia obciążenia itp.), Ale zdecydowanie więcej pracy trzeba skonfigurować, a wbudowany moduł klastra jest niski - alternatywa złożoności, która działa dla większości ludzi.


1
czy możesz zaoferować jakieś porady dotyczące uruchamiania różnych usług opartych na nodejs na jednym urządzeniu? Np. Powiedzmy, że mam 1 serwer i chcę uruchomić myservice1.js na CpuCore1 i myservice2.js na CpuCore2. Czy mogę do tego użyć klastra? czy jest to przydatne tylko do tworzenia sklonowanych usług?
UpTheCreek,

6
Powinieneś o to zadać pytanie! (i skopiuję ten komentarz jako twoją pierwszą odpowiedź). To, co chcesz zrobić, jest naprawdę bardzo proste. Tak naprawdę nie potrzebujesz „klastra”, wystarczy uruchomić dwie różne usługi węzłów. Dwa skrypty, dwa procesy, dwa porty. Na przykład, możesz mieć serviceA nasłuchuj na 3000 i serviceB nasłuchuj na 3001. Każda z tych usług może używać „klastra”, aby mieć ponad 1 pracowników i okresowo je przetwarzać itp. Następnie możesz skonfigurować Nginx do nasłuchiwania na porcie 80 i przekierowania do poprawna usługa oparta na przychodzącym nagłówku „Host” i / lub ścieżce URL.
Dave Dopson,

1
Dzięki. Zadałem już powiązane pytanie - opisałeś prawie to, co miałem na myśli, ale nie jestem pewien, jak celować w rdzenie procesora (gdy używasz czegoś takiego jak na zawsze).
UpTheCreek,

Świetna odpowiedź ddopson. Jaki jest najlepszy sposób, aby dwa procesy węzłowe komunikowały się ze sobą na tym samym komputerze? Czy istnieje szybszy protokół niż TCP, gdy są one na tym samym komputerze?
winduptoy

1
@Serob_b - cóż, tak. Uruchamianie aplikacji Node.js na wielu komputerach jest bardzo powszechne. Nie potrzeba do tego biblioteki. Wystarczy uruchomić kod na wielu komputerach i rozdzielić obciążenie między nimi. Projektowanie oprogramowania w taki sposób, aby skalowało się (tzn. Przechowuje stan w jakiejś zewnętrznej usłudze danych, a nie utrzymuje go w pamięci) - to twoje zadanie.
Dave Dopson

44

Jedną z metod byłoby uruchomienie wielu instancji node.js na serwerze, a następnie umieszczenie przed nimi modułu równoważenia obciążenia (najlepiej nieblokującego, takiego jak nginx).


36
node.js działa tak szybko, jak nginx, możesz umieścić moduł równoważenia obciążenia node.js przed serwerami node.js, jeśli chcesz również :)
Mike

26
Ryan specjalnie powiedział, żeby tego nie robić, dopóki węzeł nie będzie bardziej stabilny. Najlepszym sposobem jest uruchomienie nginx przed węzłem.
resopollution

2
tak jak w przypadku nginx przed węzłem, nie rozwiąże pewnych problemów, takich jak kolejka w pamięci. 2 instancje węzłów nie będą mogły uzyskać dostępu do swojej kolejki.
resopollution

5
Ponadto nginx nie obsługuje w pełni protokołu HTTP 1.1, więc nie można prokurentować takich rzeczy jak WebSockets.
ashchristopher

2
@mikeal, resopollution - Jestem zdecydowanie po stronie Nginx. Wielokrotnie uderzyłem w Node.js (brak stacktrace, po prostu umiera). Nigdy nie rozbiłem Nginx. Nginx po wyjęciu z pudełka jest skonfigurowany z różnego rodzaju rozsądnymi przepustnicami. Node.js domyślnie będzie nadal akceptował nowe połączenia, zamiast obsługiwać istniejące, dopóki pudełko nie ulegnie awarii ... tak, całe pudełko; Zepsułem jądro na pudełku CentOS5 przez testowanie węzła Node (teraz to tak naprawdę nie powinno się zdarzyć). Przyszedłem trochę i widzę świetlaną przyszłość dla Node, potencjalnie włączając dedykowane role typu LB. Po prostu jeszcze nie.
Dave Dopson

30

Ryan Dahl odpowiada na to pytanie podczas wykładu technicznego, który wygłosił w Google zeszłego lata. Parafrazując: „po prostu uruchom wiele procesów węzłowych i użyj czegoś rozsądnego, aby umożliwić im komunikację, np. IPC w stylu sendmsg () lub tradycyjne RPC”.

Jeśli chcesz od razu zabrudzić sobie ręce, sprawdź moduł spark2 Forever . To sprawia, że ​​odradzanie wielu procesów węzłowych jest niezwykle łatwe. Obsługuje konfigurowanie udostępniania portów, aby każdy z nich mógł akceptować połączenia z tym samym portem, a także automatycznie się odradzał, jeśli chcesz mieć pewność, że proces zostanie zrestartowany, jeśli / kiedy umrze.

AKTUALIZACJA - 11.11.11 : Wydaje się, że w społeczności węzłów istnieje konsensus, że klaster jest teraz preferowanym modułem do zarządzania wieloma instancjami węzłów na maszynie. Zawsze jest też warte obejrzenia.


8
Forever i Cluster robią bardzo różne rzeczy. Możesz nawet użyć obu. Na zawsze wznawia proces po jego śmierci. Klaster zarządza wieloma pracownikami.
Używałbyś

4
ponadto moduł learnboost jest w dużej mierze wypierany przez wersję klastra zapisaną w Node v0.6.x (ostrzeżenie: powierzchnia API jest
inna

@broofa W jaki sposób domyślny IPC jest porównywany do powiedzmy, że użycie redis lub memcache po prostu wysyła łańcuch / dane / tablice pomiędzy procesami? Który sposób byłby szybszy?
NiCk Newman

1
@ Broofa, IPC ma ogromne koszty ogólne w porównaniu z prawdziwą pamięcią współdzieloną, którą są w stanie zrobić Java i C.
Pacerier

@Pacerier Prawda, ale pamięć współużytkowana rozwiązuje problem skalowania tylko w kontekście jednego hosta, bez rozwiązywania problemów z makrami potrzebnych do skalowania na wielu hostach. Tj. Jak biegać w chmurze.
broofa

20

Możesz użyć modułu klastra . Sprawdź to .

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

Wiele węzłów wykorzystuje wszystkie dostępne rdzenie.
Zajrzyj na http://github.com/kriszyp/multi-node .

Dla prostszych potrzeb możesz uruchomić wiele kopii węzła na różnych numerach portów i umieścić przed nimi moduł równoważenia obciążenia.


12

Node Js obsługuje klastrowanie, aby w pełni wykorzystać możliwości twojego procesora. Jeśli nie korzystasz z klastra, prawdopodobnie marnujesz swoje możliwości sprzętowe.

Klastrowanie w Node.js pozwala tworzyć osobne procesy, które mogą współużytkować ten sam port serwera. Na przykład, jeśli uruchamiamy jeden serwer HTTP na porcie 3000, jest to jeden serwer działający na jednym wątku na jednym rdzeniu procesora.

Kod pokazany poniżej pozwala ci na klastrowanie twojej aplikacji. Ten kod jest oficjalnym kodem reprezentowanym przez 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.
}

sprawdź ten artykuł, aby uzyskać pełny samouczek


11

Jak wspomniano powyżej, klaster skaluje i równoważy Twoją aplikację we wszystkich rdzeniach.

dodając coś podobnego

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

Zrestartuje wszystkich nieudanych pracowników.

W dzisiejszych czasach wiele osób woli również PM2 , który obsługuje klastrowanie i oferuje kilka ciekawych funkcji monitorowania .

Następnie dodaj Nginx lub HAProxy przed kilkoma maszynami działającymi z klastrowaniem, a masz wiele poziomów przełączania awaryjnego i znacznie większą pojemność.


3
PM2 doskonale nadaje się do użytku produkcyjnego. Narzędzia do monitorowania pomogły mi rozwiązać problemy z pamięcią w aplikacjach.
mbokil

7

Przyszła wersja węzła pozwoli ci na rozwidlenie procesu i przekazanie do niego wiadomości, a Ryan stwierdził, że chce znaleźć sposób na współdzielenie programów obsługi plików, więc nie będzie to prosta implementacja Web Workera.

W tej chwili nie jest to łatwe rozwiązanie, ale wciąż jest bardzo wcześnie, a node jest jednym z najszybciej rozwijających się projektów open source, jakie kiedykolwiek widziałem, więc spodziewaj się czegoś niesamowitego w najbliższej przyszłości.


7

Spark2 jest oparty na Spark, który nie jest już obsługiwany. Klaster jest jego następcą i ma kilka fajnych funkcji, takich jak tworzenie jednego procesu roboczego na rdzeń procesora i odradzanie martwych pracowników.


Oryginalne pytanie i wiele z tych odpowiedzi ma kilka miesięcy, a węzeł porusza się tak szybko, że doceniam to, że dodaliście blub na temat Klastra. Po spojrzeniu na Cluster i jego przykłady, wygląda dokładnie tak , jak ja (lub OP?) Chcę dla Węzła, dzięki!
Riyad Kalla,

5

Korzystam z pracownika Node do uruchamiania procesów w prosty sposób z mojego głównego procesu. Wygląda na to, że działa świetnie, a my czekamy na oficjalny sposób.


1
dlaczego węzeł robot przykład.js nie może działać, mój węzeł ma wersję 0.3.3 wcześniejszą
guilin 桂林

5

Nowym dzieckiem na tym bloku jest „Up” LearnBoost .

Zapewnia „ponowne ładowanie bez przestojów” i dodatkowo tworzy wielu pracowników (domyślnie liczbę procesorów, ale można je konfigurować), aby zapewnić najlepsze ze wszystkich światów.

Jest nowy, ale wydaje się dość stabilny i z radością go używam w jednym z moich bieżących projektów.


5

Klaster Moduł pozwala na wykorzystanie wszystkich rdzeni komputerze. W rzeczywistości możesz to wykorzystać w zaledwie 2 poleceniach i bez dotykania kodu za pomocą bardzo popularnego menedżera procesów pm2 .

npm i -g pm2
pm2 start app.js -i max

4

Możesz uruchomić aplikację node.js na wielu rdzeniach, używając modułu klastra w połączeniu z OS modułem , który może być używany do wykrywania liczby posiadanych procesorów.

Na przykład wyobraźmy sobie, że masz servermoduł, który uruchamia prosty serwer HTTP na backendie i chcesz go uruchomić dla kilku procesorów:

// 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();
}


0

Możliwe jest również zaprojektowanie usługi sieciowej jako kilku niezależnych serwerów nasłuchujących na gniazdach unix, dzięki czemu można wcisnąć funkcje takie jak przetwarzanie danych do osobnych procesów.

Jest to podobne do większości architektur serwerów WWW służących do przeszukiwania / baz danych, w których proces cgi obsługuje logikę biznesową, a następnie wypycha i ściąga dane przez gniazdo unix do bazy danych.

różnica polega na tym, że przetwarzanie danych jest zapisywane jako serwer węzła nasłuchujący na porcie.

jest bardziej złożony, ale ostatecznie to właśnie tam musi iść rozwój wielordzeniowy. architektura wieloprocesowa wykorzystująca wiele komponentów dla każdego żądania WWW.


0

Możliwe jest skalowanie NodeJS do wielu skrzynek za pomocą modułu równoważenia obciążenia czystego TCP (HAProxy) przed wieloma skrzynkami, z których każdy uruchamia jeden proces NodeJS.

Jeśli masz trochę wspólnej wiedzy do dzielenia się między wszystkimi instancjami, możesz użyć centralnego sklepu Redis lub podobnego, do którego można uzyskać dostęp ze wszystkich instancji procesu (np. Ze wszystkich skrzynek)


O ile nie masz procesorów jednordzeniowych na tych serwerach, nie wykorzysta to całej pojemności procesora (chyba że robisz coś innego).
UpTheCreek,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.