A Node.js kiszolgáló méretezése fürtözéssel

A skálázhatóság aktuális téma a technikában, és minden programozási nyelv vagy keretrendszer megadja a maga módját a nagy terhelések kezelésére.

Ma egy egyszerű és egyértelmű példát fogunk látni a Node.js fürtözésről. Ez egy olyan programozási technika, amely segít párhuzamosítani a kódot és felgyorsítani a teljesítményt.

„A Node.js egyetlen példánya fut egyetlen szálon. A többmagos rendszerek előnyeinek kihasználása érdekében a felhasználó néha a Node.js folyamatok fürtjét akarja elindítani a terhelés kezelésére. "

- Node.js dokumentáció

Egy egyszerű webszervert fogunk létrehozni a Koa segítségével, amely használat szempontjából valóban hasonló az Express-hez.

A teljes példa ebben a Github-tárban érhető el.

Amit építeni fogunk

Felépítünk egy egyszerű webszervert, amely a következőképpen fog működni:

  1. Szerverünk POSTkérést fog kapni , úgy teszünk, mintha a felhasználó képet küldene nekünk.
  2. Képeket másolunk a fájlrendszerből egy ideiglenes könyvtárba.
  3. Függőlegesen megfordítjuk a Jimp, a Node.js képfeldolgozó könyvtárának használatával.
  4. Mentjük a fájlrendszerbe.
  5. Töröljük, és választ küldünk a felhasználónak.

Természetesen ez nem egy valós alkalmazás, de elég közel áll ahhoz. Csak a fürtözés használatának előnyeit szeretnénk felmérni.

A projekt beállítása

Megyek használatra yarntelepíteni én függőségek és inicializálni én projekt:

Mivel a Node.js egyszálú, ha a webszerverünk összeomlik, az addig nem működik, amíg más folyamat nem indítja újra. Szóval örökre telepítjük, egy egyszerű démon, amely újraindítja webszerverünket, ha valaha is összeomlik.

Telepítjük a Jimp-et, a Koa-t és a Koa Routert is.

Első lépések Koával

Ezt a mappastruktúrát kell létrehoznunk:

Van egy srcmappánk, amely két JavaScript fájlt tartalmaz: cluster.jsés standard.js.

Az első lesz az a fájl, ahol kísérletezni fogunk a clustermodullal. A második egy egyszerű Koa szerver, amely fürtözés nélkül fog működni.

A modulekönyvtárban két fájlt fogunk létrehozni: job.jsés log.js.

job.jselvégzi a képmanipulációs munkát. log.jsnaplózza az adott folyamat során bekövetkező minden eseményt.

A Napló modul

A Log modul egy egyszerű függvény lesz, amely elvesz egy argumentumot, és beírja a stdout(hasonlóhoz console.log).

A napló elejéhez hozzáfűzi az aktuális időbélyeget is. Ez lehetővé teszi számunkra, hogy ellenőrizzük, mikor kezdődött egy folyamat, és megmérhettük annak teljesítményét.

A Job modul

Őszinte leszek, ez nem egy szép és szuperoptimalizált szkript. Ez csak egy könnyű munka, amely lehetővé teszi számunkra, hogy megterheljük a gépünket.

A Koa Webszerver

Nagyon egyszerű webszervert fogunk létrehozni. Két útvonalon fog válaszolni, két különböző HTTP módszerrel.

GET kérést a következő napon tudunk teljesíteni //localhost:3000/. A Koa egy egyszerű szöveggel válaszol, amely megmutatja az aktuális PID-t (folyamatazonosítót).

A második útvonal csak a POST kéréseket fogadja el az /flipútvonalon, és elvégzi az imént létrehozott munkát.

Létrehozunk egy egyszerű köztes szoftvert is, amely beállítja a X-Response-Timefejlécet. Ez lehetővé teszi számunkra a teljesítmény mérését.

Nagy! Most már elkezdhetjük szerverünk gépelését node ./src/standard.jsés tesztelhetjük az útjainkat.

A probléma

Használjuk a gépemet szerverként:

  • Macbook Pro 15 hüvelykes 2016
  • 2,7 GHz-es Intel Core i7
  • 16 GB RAM

Ha POST kérést küldök, akkor a fenti szkript ~ 3800 ezredmásodperc alatt küld választ. Nem is olyan rossz, tekintve, hogy a kép, amin jelenleg dolgozom, kb. 6,7 MB.

Megpróbálhatok további kéréseket benyújtani, de a válaszidő nem csökken túlságosan. A kéréseket ugyanis egymás után fogjuk végrehajtani.

Szóval, mi történne, ha megpróbálnék 10, 100, 1000 egyidejű kérést benyújtani?

Készítettem egy egyszerű Elixir szkriptet, amely több egyidejű HTTP kérést hajt végre:

Az Elixirt választottam, mert nagyon egyszerű párhuzamos folyamatokat létrehozni, de bármit használhatsz, amit szeretsz!

Tíz egyidejű kérés tesztelése - fürtözés nélkül

Mint láthatja, az iex-ből (egy Elixir REPL) 10 párhuzamos folyamatot hozunk létre.

A Node.js szerver azonnal lemásolja a képünket, és elkezdi lapozni.

Az első válasz naplózásra kerül 16, az utolsó pedig 40 másodperc múlva.

Ilyen drámai teljesítménycsökkenés! Csak 10 egyidejű kéréssel,950% -kal csökkentettük a webszerver teljesítményét!

A klaszterezés bemutatása

Emlékszel arra, amit a cikk elején említettem?

A többmagos rendszerek előnyeinek kihasználása érdekében a felhasználó néha a Node.js folyamatok fürtjét akarja elindítani a terhelés kezelésére.

Attól függően, hogy melyik kiszolgálón fogjuk futtatni a Koa alkalmazást, eltérő számú magunk lehet.

Minden mag felelős a rakomány egyénileg történő kezeléséért. Alapvetően minden HTTP-kérést egyetlen mag fog kielégíteni.

Így például - a gépem, amelynek nyolc magja van, nyolc egyidejű kérést fog kezelni.

Most megszámolhatjuk, hogy hány osmodulunk van a modulnak köszönhetően :

A cpus()módszer olyan objektumok tömbjét adja vissza, amelyek leírják a CPU-kat. Összeköthetjük a hosszát egy állandóval, amelyet hívunk numWorkers, mert ennyi dolgozót fogunk használni.

Most már készen állunk a clustermodul igénylésére.

Most arra van szükségünk, hogy fő folyamatunkat Nkülön folyamatokra osszuk fel.

Meghívjuk a fő folyamatunkat masterés a többi folyamatot workers.

A Node.js clustermodul az úgynevezett metódust kínálja isMaster. Egy logikai értéket ad vissza, amely megmondja, hogy az aktuális folyamatot egy dolgozó vagy mester irányítja-e:

Nagy. Az aranyszabály itt az, hogy nem akarjuk a Koa alkalmazásunkat a master folyamat alatt kiszolgálni.

Minden munkavállaló számára szeretnénk létrehozni egy Koa alkalmazást, így amikor bejön egy kérés, az első ingyenes munkavállaló gondoskodik róla.

A cluster.fork()módszer megfelel a célunknak:

Ok, eleinte ez kissé trükkös lehet.

Amint a fenti szkriptből látható, ha a szkriptünket a master folyamat hajtotta végre, akkor konstansnak nevezzük a nevet workers. Ez létrehoz egy munkatársat a processzorunk minden egyes magjához, és tárolja a rájuk vonatkozó összes információt.

Ha bizonytalan az elfogadott szintaxissal kapcsolatban, akkor a használata […Array(x)].map()megegyezik a következőkkel:

Inkább változatlan értékeket használok, miközben fejlesztek egy nagy párhuzamosságú alkalmazást.

Koa hozzáadása

Mint korábban mondtuk, nem akarjuk a Koa alkalmazásunkat a master folyamat alatt kiszolgálni.

Másoljuk át a Koa alkalmazásstruktúránkat az elseutasításba, így biztosak leszünk abban, hogy azt egy dolgozó fogja kiszolgálni:

Amint láthatja, a rendezvényre néhány eseményhallgatót is felvettünk isMaster:

Az első elmondja, hogy új munkás született. A második új munkavállalót hoz létre, amikor egy másik dolgozó összeomlik.

Így a fő folyamat csak az új munkások létrehozásáért és azok összehangolásáért lesz felelős. Minden dolgozó kiszolgálja a Koa egy példányát, amely elérhető lesz a :3000kikötőben.

Tíz egyidejű kérés tesztelése - fürtözéssel

Mint látható, az első válaszunk körülbelül 10, az utolsó pedig körülbelül 14 másodperc múlva érkezett. Elképesztő fejlődés az előző 40 másodperces válaszidőhöz képest!

Tíz egyidejű kérést tettünk, és a Koa szerver nyolcat azonnal elfogadott. Amikor az első dolgozó elküldte válaszát az ügyfélnek, a fennmaradó kérelmek egyikét elfogadta és feldolgozta!

Következtetés

A Node.js elképesztő kapacitással képes kezelni a nagy terheléseket, de nem lenne bölcs dolog leállítani egy kérést, amíg a szerver nem fejezi be a folyamatát.

Valójában a Node.js webszerverek több ezer egyidejű kérést tudnak kezelni, ha azonnal választ küld az ügyfélnek.

A legjobb gyakorlat az lenne, ha egy pub / sub üzenetkezelő felületet adna hozzá a Redis vagy bármely más csodálatos eszköz használatával. Amikor az ügyfél kérést küld, a szerver valós idejű kommunikációt indít más szolgáltatásokkal. Ez átveszi a felelősséget a drága munkákért.

A terheléselosztók szintén sokat segítenek a nagy forgalmi terhek felosztásában.

Ismét a technológia végtelen lehetőségeket kínál számunkra, és biztosan megtaláljuk a megfelelő megoldást alkalmazásunk végtelenre és azon túlra történő skálázására!