
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:
- Szerverünk
POST
kérést fog kapni , úgy teszünk, mintha a felhasználó képet küldene nekünk. - Képeket másolunk a fájlrendszerből egy ideiglenes könyvtárba.
- Függőlegesen megfordítjuk a Jimp, a Node.js képfeldolgozó könyvtárának használatával.
- Mentjük a fájlrendszerbe.
- 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 yarn
telepí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 src
mappá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 cluster
modullal. A második egy egyszerű Koa szerver, amely fürtözés nélkül fog működni.
A module
könyvtárban két fájlt fogunk létrehozni: job.js
és log.js
.
job.js
elvégzi a képmanipulációs munkát. log.js
napló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-Time
fejlé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 os
modulunk 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 cluster
modul igénylésére.
Most arra van szükségünk, hogy fő folyamatunkat N
külön folyamatokra osszuk fel.
Meghívjuk a fő folyamatunkat master
és a többi folyamatot workers
.
A Node.js cluster
modul 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 else
utasí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 :3000
kikö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!