de Michele Riva

Cum să vă scalați serverul Node.js utilizând clustering

Cum sa va scalati serverul Nodejs utilizand clustering

Scalabilitatea este un subiect fierbinte în tehnologie și fiecare limbaj de programare sau cadru oferă propriul mod de a gestiona o mare cantitate de trafic.

Astăzi, vom vedea un exemplu ușor și simplu despre clusterizarea Node.js. Aceasta este o tehnică de programare care vă va ajuta să vă paralelați codul și să accelerați performanța.

„O singură instanță a Node.js rulează într-un singur fir. Pentru a profita de sistemele multi-core, utilizatorul va dori uneori să lanseze un cluster de procese Node.js pentru a face față sarcinii. ”
Documentație Node.js

Vom crea un server web simplu folosind Koa, care este cu adevărat similar cu Expres din punct de vedere al utilizării.

Exemplul complet este disponibil în acest depozit Github.

Ce vom construi

1612035727 897 Cum sa va scalati serverul Nodejs utilizand clustering

Vom construi un server web simplu care va acționa după cum urmează:

  1. Serverul nostru va primi un POST cerere, ne vom preface că utilizatorul ne trimite o imagine.
  2. Vom copia o imagine din sistemul de fișiere într-un director temporar.
  3. Îl vom răsuci vertical folosind Jimp, o bibliotecă de procesare a imaginilor pentru Node.js.
  4. Îl vom salva în sistemul de fișiere.
  5. Îl vom șterge și vom trimite un răspuns utilizatorului.

Desigur, aceasta nu este o aplicație din lumea reală, dar este destul de apropiată de una. Vrem doar să măsurăm beneficiile utilizării clusterizării.

Configurarea proiectului

Voi folosi yarn pentru a-mi instala dependențele și a inițializa proiectul meu:

Deoarece Node.js este cu un singur thread, dacă serverul nostru web se blochează, acesta va rămâne oprit până când un alt proces îl va reporni. Deci vom instala pentru totdeauna, un demon simplu care va reporni serverul nostru web dacă se blochează vreodată.

Vom instala, de asemenea Jimp, Koa și Koa Router.

Noțiuni de bază cu Koa

Aceasta este structura de dosare pe care trebuie să o creăm:

1612035728 956 Cum sa va scalati serverul Nodejs utilizand clustering

Vom avea o src folder care conține două fișiere JavaScript: cluster.js și standard.js .

Primul va fi fișierul în care vom experimenta cu cluster modul. Al doilea este un server Koa simplu care va funcționa fără niciun cluster.

În module director, vom crea două fișiere: job.js și log.js.

job.js va efectua lucrarea de manipulare a imaginii. log.js va înregistra fiecare eveniment care are loc în timpul procesului respectiv.

Modulul Jurnal

Modulul jurnal va fi o funcție simplă care va lua un argument și îl va scrie în stdout (similar cu console.log).

De asemenea, va adăuga marca de timp curentă la începutul jurnalului. Acest lucru ne va permite să verificăm când a început un proces și să măsurăm performanța acestuia.

Modulul Job

Voi fi sincer, acesta nu este un scenariu frumos și super-optimizat. Este doar o treabă ușoară care ne va permite să ne stresăm mașina.

The Koa Webserver

Vom crea un server web foarte simplu. Va răspunde pe două rute cu două metode HTTP diferite.

Vom putea efectua o solicitare GET pe http://localhost:3000/. Koa va răspunde cu un text simplu care ne va arăta PID-ul curent (id-ul procesului).

A doua rută va accepta numai cereri POST pe /flip și va îndeplini jobul pe care tocmai l-am creat.

De asemenea, vom crea un middleware simplu care va seta un X-Response-Time antet. Acest lucru ne va permite să măsurăm performanța.

Grozav! Acum putem începe tastarea serverului nostru node ./src/standard.js și testați traseele noastre.

Problema

Cum sa va scalati serverul Nodejs utilizand clustering
Imaginea pe care o manipulez în prezent (prin Unsplash)

Să folosim mașina mea ca server:

  • Macbook Pro 15-inch 2016
  • Intel Core i7 de 2,7 GHz
  • 16 GB RAM

Dacă fac o solicitare POST, scriptul de mai sus îmi va trimite un răspuns în ~ 3800 milisecunde. Nu este atât de rău, având în vedere că imaginea la care lucrez în prezent este de aproximativ 6,7 MB.

Pot încerca să fac mai multe solicitări, dar timpul de răspuns nu va scădea prea mult. Acest lucru se datorează faptului că solicitările vor fi efectuate secvențial.

Deci, ce s-ar întâmpla dacă aș încerca să fac 10, 100, 1000 de cereri simultane?

Am realizat un script Elixir simplu care efectuează mai multe cereri HTTP simultane:

Am ales Elixir pentru că este foarte ușor să creezi procese paralele, dar poți folosi orice preferi!

Testarea a zece cereri concurente – fără grupare

După cum puteți vedea, generăm 10 procese simultane din iex-ul nostru (un Elixir REPL).

Serverul Node.js va copia imediat imaginea noastră și va începe să o întoarcă.
Primul răspuns va fi înregistrat după 16 secunde și ultimul după 40 de secunde.

O astfel de performanță dramatică scade! Cu doar 10 cereri simultane, am redus performanța serverului web cu 950%!

Introducerea clusteringului

1612035728 827 Cum sa va scalati serverul Nodejs utilizand clustering
Toate creditele către Pexels

Vă amintiți ce am menționat la începutul articolului?

Pentru a profita de sistemele multi-core, utilizatorul va dori uneori să lanseze un cluster de procese Node.js pentru a gestiona sarcina.

În funcție de serverul pe care îl vom rula aplicația Koa, am putea avea un număr diferit de nuclee.

Fiecare miez va fi responsabil pentru manipularea individuală a încărcăturii. Practic, fiecare cerere HTTP va fi satisfăcută de un singur nucleu.

De exemplu, mașina mea, care are opt nuclee, va gestiona opt cereri concurente.

Acum putem număra câte procesoare avem datorită os modul:

cpus() metoda va returna o serie de obiecte care descriu procesoarele noastre. Îi putem lega lungimea de o constantă care va fi numită numWorkers, pentru că acesta este numărul de lucrători pe care îi vom folosi.

Acum suntem gata să solicităm cluster modul.

Acum avem nevoie de o modalitate de a împărți procesul nostru principal în N procese distincte.
Vom apela la procesul nostru principal master și celelalte procese workers.

Node.js cluster Modulul oferă o metodă numită isMaster. Acesta va returna o valoare booleană care ne va spune dacă procesul curent este dirijat de un lucrător sau maestru:

Grozav. Regula de aur aici este că nu vrem să ne servim aplicația Koa în cadrul procesului master.

Vrem să creăm o aplicație Koa pentru fiecare lucrător, așa că atunci când vine o cerere, primul lucrător gratuit se va ocupa de ea.

cluster.fork() metoda se va potrivi scopului nostru:

Ok, la început, poate fi puțin dificil.

După cum puteți vedea în scriptul de mai sus, dacă scriptul nostru a fost executat de procesul master, vom declara o constantă numită workers. Aceasta va crea un lucrător pentru fiecare nucleu al procesorului nostru și va stoca toate informațiile despre acestea.

Dacă nu sunteți sigur cu privire la sintaxa adoptată, utilizați […Array(x)].map() este la fel ca:

Prefer doar să folosesc valori imuabile în timp ce dezvolt o aplicație cu concurență ridicată.

Adăugând Koa

1612035729 415 Cum sa va scalati serverul Nodejs utilizand clustering
Toate creditele către Pexels

Așa cum am spus mai devreme, nu vrem să ne difuzăm aplicația Koa în cadrul procesului master.

Să copiem structura aplicației Koa în else declarație, deci vom fi siguri că va fi comunicată de un lucrător:

După cum puteți vedea, am adăugat și câțiva ascultători de evenimente în isMaster afirmație:

Primul ne va spune că a fost creat un nou lucrător. Al doilea va crea un muncitor nou atunci când un alt muncitor se prăbușește.

În acest fel, procesul master va fi responsabil doar de crearea de noi lucrători și de orchestrarea acestora. Fiecare lucrător va servi o instanță de Koa care va fi accesibilă pe :3000 port.

Testarea a zece cereri simultane – cu clustering

După cum puteți vedea, am primit primul nostru răspuns după aproximativ 10 secunde, iar ultimul după aproximativ 14 secunde. Este o îmbunătățire uimitoare față de timpul de răspuns precedent de 40 de secunde!

Am făcut zece cereri simultane, iar serverul Koa a preluat opt ​​dintre ele imediat. Când primul lucrător și-a trimis răspunsul către client, acesta a preluat una dintre cererile rămase și l-a procesat!

Concluzie

Node.js are o capacitate uimitoare de gestionare a încărcărilor mari, dar nu ar fi înțelept să opriți o cerere până când serverul nu își termină procesul.

De fapt, serverele web Node.js pot gestiona mii de cereri simultane numai dacă trimiteți imediat un răspuns clientului.

O bună practică ar fi să adăugați o interfață de mesagerie pub / sub folosind Redis sau orice alt instrument uimitor. Când clientul trimite o cerere, serverul începe o comunicare în timp real cu alte servicii. Acest lucru se ocupă de locuri de muncă scumpe.

Echilibratoarele de sarcină ar ajuta, de asemenea, să împartă foarte mult traficul mare.

Încă o dată, tehnologia ne oferă posibilități nesfârșite și suntem siguri că vom găsi soluția potrivită pentru a scala aplicația noastră la infinit și nu numai!