"Ikke blokker event-løkken..." - du har sikkert hørt denne setningen mange ganger... Det overrasker meg ikke, for det er en av de viktigste forutsetningene når du jobber med Node. Men det er også en annen "ting" som du bør avstå fra å blokkere - Worker Pool. Hvis du glemmer det, kan det ha en betydelig innvirkning på applikasjonens ytelse og til og med dens sikkerhet.
Tråder
Det viktigste å huske: Det finnes to typer tråder i Node.js: Main Thread - som håndteres av Hendelsessløyfe, og Arbeidstakerpool (trådpool) - som er en pool av tråder - og
takket være libuv. Hver av dem har forskjellige oppgaver. Den første har som mål å håndtere ikke-blokkerende I/O-operasjoner, mens den andre er ansvarlig for CPU-intensivt arbeid og blokkerende I/O.
Men hva er en tråd, og hvordan er den forskjellig fra en prosess? Det er flere forskjeller, men den viktigste for oss er hvordan minnet allokeres til dem. Du kan tenke på en prosess som på en applikasjon. Inne i hver prosess er det en del av minnet som er dedikert bare til denne prosessen. Den ene prosessen har altså ikke tilgang til minnet til den andre, og denne egenskapen sørger for høy sikkerhet. For å etablere kommunikasjon mellom dem, må vi gjøre noe arbeid. Tråder er annerledes. Tråder kjører inne i en prosess og deler det samme minnet, så det er ikke noe problem i det hele tatt med tråder som deler data.
Det er imidlertid én ting som skaper problemer. Det kalles "race condition". Trådene kan kjøre samtidig, så hvordan vet vi hvilken som avsluttes først? Det kan hende at første gang du kjører den, slutter den første operasjonen først, og neste gang kan det vise seg å være motsatt, og den andre operasjonen slutter før den første. Tenk deg å jobbe med skrive-/leseoperasjoner under slike forhold! Et mareritt! Det er noen ganger veldig vanskelig å skrive korrekt kode i et flertrådet miljø.
De flertrådede språkene har også et stort minneoverhead fordi de oppretter en egen tråd for hver forespørsel, så hvis du vil ringe 1000 forespørsler, oppretter de 1000 tråder.
Hvordan håndtere et slikt problem? Bruk en enkelt tråd i stedet! Og det er det som Knutepunkt tilbyr deg.
Som en JavaScript utvikler Jeg oppfordrer deg til å se film
der Bart Belder tydelig forklarer konseptet med hendelsessløyfen. Diagrammet ovenfor er hentet fra presentasjonen hans. Og hvis du ikke kjenner disse begrepene i det hele tatt, både Knutepunkt og Libuv har utmerket dokumentasjon 🙂 .
Om blokkering
I JavaScript-utvikling industrien sier de at fordi Knutepunkt er enkelttrådet og ikke-blokkerende, kan du oppnå høyere samtidighet med de samme ressursene enn med flertrådede løsninger. Det er sant, men det er ikke så vakkert og enkelt som det kan virke.
Siden Node.js er enkelttrådet (JS-delen), vil CPU-intensive oppgaver blokkere alle forespørsler som pågår til den aktuelle oppgaven er fullført. Så det er sant at i Node.js kan du blokkere alle forespørsler bare fordi en av dem inneholdt en blokkerende instruksjon. Blokkerende kode betyr at det tar mer enn noen få millisekunder å fullføre. Men ikke forveksle lang responstid med blokkering. Svaret fra databasen kan ta svært lang tid, men det blokkerer ikke prosessen (applikasjonen).
Blokkerende metoder utføres synkront, mens ikke-blokkerende metoder utføres asynkront.
Hvordan kan du bremse (eller blokkere) hendelsessløyfen din?
- sårbar regex - et sårbart regulært uttrykk er et uttrykk som kan ta eksponentiell tid å behandle; du kan lese mer om dem her her,
- JSON-operasjoner på store objekter,
- ved hjelp av synkrone API-er fra Knutepunkt kjernemoduler i stedet for asynkrone versjoner; alle I/O-metodene i Node.js-standardbiblioteket har også sine asynkrone versjoner,
- andre programmeringsfeil, som synkrone uendelige løkker.
I så fall, siden Worker Pool bruker en pool av tråder, er det mulig å blokkere dem også? Dessverre, ja 🙁 ... Knutepunkt er basert på en filosofi én tråd for mange klienter.
La oss anta at en gitt oppgave som utføres av en bestemt Worker, er svært kompleks og trenger mer tid for å bli ferdig. Dette fører til at Workern blokkeres, og den kan ikke brukes til å utføre andre ventende oppgaver før instruksjonene er utført. Som du sikkert har gjettet nå, kan det påvirke ytelsen. Du kan forhindre slike problemer ved å minimere variasjonen i oppgavetider ved å bruke oppgavepartisjonering.
Konklusjon
Unngå blokkering, det er helt sikkert. Hvis du bare kan, bør du alltid velge asynkrone versjoner av standardbibliotekets API-er. Ellers kan klienten oppleve flere problemer etter å ha kjørt appen din, fra redusert gjennomstrømning til fullstendig tilbaketrekning, noe som er fatalt sett fra brukerens perspektiv.
Les mer om dette:
Derfor bør du (sannsynligvis) bruke Typescript
Hvordan unngår man å drepe et prosjekt med dårlig kodingspraksis?
Strategier for datahenting i NextJS