nodejs sok magvas környezetben

Fórumok

Sziasztok!

Már eddig is szembejött a nodejs infrastruktúra/programnyelv, de nem gondoltam, hogy foglalkoznom kell vele. De nini itt lett egy CRM rendszer, amit ebben írtak. Elég sokat olvastam róla, de kíváncsi lennék valós tapasztalatokra.

Adott ugye egy egyszálas működés, amelyben alacsonyan kell tartani az eventloop latency-t, azaz nem megfogni azt az egy szálat és erre adottak az aszinkron hívások. (Hogy miért pont async-kel jelölik a szinkron =rossz/nem hatékony hívásokat, azon én személy szerint átléptem). Egy CPU magon is elfut szépen, de van beépített cluster funkciója, amivel fork-olja saját magát és több CPU-n tud futni. Alapértelmezetten annyi példányban fut, amennyi CPU (mag) jelen van. Ezt támogatja a PM2 futattó rendszer is, ez az irány a jövő (sic!).

Az egész nodejs szépen fut VPS-eken is, pont amennyi CPU kell neki. De - itt jön a kérdés - mi van akkor, ha egy sok magos (32+) hardveren felhasználókat nem zárom be a saját VPS-eikbe, nem a VPS-ek átskálázásával (több CPU) adok nekik löketet, hanem host/guest nélkül az alkalmazásoknak egyenként adok CPU-t, egyenként állítom, hogy a 32-ből mennyit kapjanak? Security kérdésekkel egyelőre nem foglakozunk, állítólag megy 80-as (<1000) port (valami nodejs express?) nem root userrel is, azaz tudom őket korlátozni. (Ha eltekintek az npm cache-től, akkor jail-be is rakhatom őket).

A fejlesztő cég is a VPS-t ajánlja, előre becsüljük meg mennyi CPU kell. De én előállnék valami jobbal, ha van :)

Hozzászólások

Hogy miért pont async-kel jelölik a szinkron =rossz/nem hatékony hívásokat, azon én személy szerint átléptem

Egyrészt nem rossz/nem hatékony, hanem I/O hívások (általában). Másrészt azért, mert nem blokkolja az event loopot amíg előáll az eredmény, addig futhat más kód, cserébe az eredményt valamilyen callbacken keresztül (vagy async függvényben await után) kapod meg.

Pl.: https://repl.it/@tiborbaksa/TechnologicalSickUnits

A run függvény két hívása egyszerre fut, ami a fizz és buzz logok összefésülődéséből, valamint a két függvény hozzávetőlegesen azonos futásidejéből látszik. A delay függvény helyére gondolatban behelyettesíthetsz bármilyen I/O függvényt.

Nekem az a sejtésem, hogy a kolléga is azon akadt fenn, amin én anno elsőre: egy ajax hívás látszólag (most tekintsünk el attól elsőre, hogy a js egyszálú) pont hogy a háttérben, szinkronban fut a UI többi folyamatával, nem async módon, azaz a UI előtt-után. A szinkron sokaknak egyenlő párhuzamos, csakhogy jön az a rész, hogy a js nem többszálú (alapból, mert tudom, webworker, hagyjuk most), ezért minden szépen sorban megy egymás után, szinkronban, de kérhetem, hogy valami visszatérése előtt fusson le sok másik többi hívás. Eszméletlen fáradt vagyok, nagyon rosszul fogalmazok, de ezen sokan fennakadtak már, és ez volt a gyökere. (Én úgy gondolom még mindig, hogy rossz az elnevezés, event loop ellenére is, de meggyőzhető vagyok.)

Ha nem válaszolnék kommentben, hát küldj privátot!

Érdekes ez a kérdés, mert ebben a kontextusban ehhez a jelentéshez vagyok szokva, de más kontextusban értem amit mondasz, pl. szinkronúszás. StackOverflown találtam ezt a választ, ami szerintem elég jól elmagyarázza. Vagyis ha a végrehajtás szinkron, akkor a feladatok függenek egymástól, ha aszinkron, akkor egymástól függetlenül, de nem feltétlenül egymással párhuzamosan futnak.

A problémám az, hogy a szinkron az egyszerre, nem egymás eredményétől függően egymás utáni dolgokat jelent, az a kauzalitás, vagy láncolás, vagy valami hasonló. Van egy olyan érzésem néha ezzel a témával kapcsolatban, főleg amikor egy JS konferencián az event loop-ot magyarázó előadó azt mondja, hogy ő se értette, ezért csinált egy kísérletet hozzá, amivel már nagyjából érti, szóval ilyenkor azt érzem, hogy a JS világban sok a nem CS major, hanem autodidakta, amivel semmi gond nem lenne, ha nem ők találnák ki az elnevezéseket :) . (Mondom ezt autodidaktaként, tudom tudom, utálom a fajtámat, pedig nem is.)

Ha nem válaszolnék kommentben, hát küldj privátot!

Igazából nem is az (a)sync kérdéskör a fő téma, azt megértettem: minden async előtag Promise-t generál, ettől Node jellgű lesz... Az igazi kérdés azonban nyitva.

próbáltam már egyszer válaszolni, de nem biztos, hogy értem a kérdésedet:

Ha az adott nodejs alkalmazás úgy van megírva, hogy képes a beépített clustering mechanizmust használva skálázódni (vagy pl. pm2-t ajánl/használ erre) akkor biztosan meg kellett adnia a fejlesztőnek valahol a kívánt subprocessek számát. Ezt vagy kivezette neked egy konfigurációs beállításba (és akkor te beállítod az igényeidnek megfelelően) vagy pedig valamilyen logika alapján maga dönti el (pl. lekérdezi az elérhető magok számát és használja az összeset). Az utóbbi esetben ha korlátozni akarod az alkalmazás CPU használatát, akkor alacsonyabb szinten kell lehatárolnod előle a többi magot (pl. dockert használsz CPU paraméterrel, vagy virtuális gépet használsz), de azt, hogy az adott helyzetben melyik a jobb, neked kell eldönteni.

Még két dolog:

- a pm2-nél ezt biztosan lehet állítani, iilletve futásidőben is matathatod, ha jól van megírva az alkalmazás akkor mindegy neki, hogy 1-2-8-16 process indul/fut/hal meg éppen

- az, hogy egy alkalmazás nem root userrel futtatva is tudjon 1024 alatti porton figyelni nem valami mágia, egyszerűen be kell neki állítani a CAP_NET_BIND_SERVICE capability-t: 

setcap 'cap_net_bind_service=+ep' /path/to/program

ez mindenre működik. Az, hogy mennyire kockázatos security szempontból, szintén adott környezet kérdése.

Köszönöm részletes válaszod!

Ugyanezeket a köröket futjuk belül is. Több admin azt mondja, hogy ő 32 (látott már 128-at is) magos gépre nem rakna egy production OS-t, azt mindenképp felvágná VPS-ekre és azokra tenné a dolgokat. Én meg csak kíváncsiságból visszakérdeztem, hogy ha a host 32 magon futtatja az OS-t, akkor miért ne mehetne ezen egy vagy sok nodejs, mintha az egy VPS lenne. És erre nem jött válasz a "szokásjogon" kívül.

80-as port ugysem fog játszani nodejs instance-onként, mert hiszen mindegyiknek saját port-ja lesz, ami nginx-en át fog 80-as porton elérhető alkalmazássá válni hostnév alapján. De köszönöm a setcap-ot!

És erre nem jött válasz a "szokásjogon" kívül.

Mert nem erre tervezték, hanem VPS/Docker/Kubernetes és egyebek alatti microservice architektúrára. Pont. Ettől persze el lehet térni indokolt esetben, de akkor fel kell készülni arra, hogy időnként forgatod, mint medve a sünt.

így már világosabb. Műszaki szempontból teljesen igazad van, valószínűleg ugyan abból a vasból konténerekkel/chroot-al több teljesítmény kihozható mintha virtuális gépekre szabdalod.

Ami viszont a nagyobb képet illeti, ez nem egy műszaki kérdés: mennyit nyersz azzal, hogy konténereket használsz virtualizáció helyett forintosítva? Ezzel szemben mennyit veszítesz azzal ha az általad kigondolt elrendezést bonyolultabb/nehezebb karban tartani, üzemeltetni, mint a "szokásjog alapján" bevált megoldást? Megéri? Manapság amikor egy iparági expert 2 havi béréből közepesen jó szervert lehet venni, hidd el, hogy nem fogod meggyőzni a vezetést azzal, hogy 20%-al kevesebb CPU idő megy a kukába a te megoldásodban ;)

"mennyit nyersz azzal, hogy konténereket használsz virtualizáció helyett forintosítva?": itt van a kutya elásva. Az én érvelésem egyik pontja volt, hogy pm2 mindenképp lesz. Mindenképp meg kell tanulni (nem túl bonyolult). De ezzel a VPS kihagyható. Azaz a VPS+PM2+sajátIP-k vs. PM2 native a választás. Ez esetben ez utóbbinak van előnye, nem?

Semmilyen más módon nem használjátok a virtualizáció átltal adott lehetőségeket (egy példa: VM snapshotok)? Ha nem akkor mindenképpen jobb választás simán a vasra tenni az applikációt.

Ami nekem továbbra sem teljesen világos, hogy ezt a CRM rendszert több példányban szeretnéd futtatni, több különböző ügyfélnek erről az egy szerverről?

A pm2 csak és kizárólag egy process manager, a nodejs puffasztott init.d-je. A node processzeket direktben is elindíthatod, a pm2 csak egy szép/rusnya felület ad hozzá, mi és hogyan váltaná itt ki a vps-t vagy egy container-t?

"A fejlesztő cég is a VPS-t ajánlja, előre becsüljük meg mennyi CPU kell. De én előállnék valami jobbal, ha van :)"

Ez utóbbi egy akkora magaslabda, hogy inkább nem csapom le

// Happy debugging, suckers
#define true (rand() > 10)