Slodzes testēšana un veiktspējas noskaņošana Node.js aplikācijām
Slodzes testēšanas metodoloģija — rīki, metrikas, vājās vietas un optimizācijas stratēģijas Node.js aplikācijām.
Veiktspēja zem slodzes ir visa atšķirība starp uzticamu un neuzticamu aplikāciju. Slodzes testēšana atklāj problēmas pirms tās skar lietotājus — un nodrošina, ka Black Friday, mārketinga kampaņa vai vīrusu saturs nesagrauj jūsu infrastruktūru.
Testēšanas metodoloģija — pieejas un scenāriji
Slodzes testu veidi
- Load test — normāla/sagaidāma slodze ilgākā periodā (30–60 min). Pārbauda, vai sistēma iztur ikdienas satiksmi. Piemērs: 100 vienlaicīgi lietotāji simulējot tipisku lietotāja ceļu
- Stress test — pakāpeniski pieaugoša slodze līdz lūzuma punktam. Atklāj sistēmas limitu un degradācijas uzvedību. Piemērs: no 50 uz 500 uz 5000 lietotājiem ik 5 minūtēs
- Soak test (endurance) — pastāvīga vidēja slodze ilgstošā periodā (2–8h vai ilgāk). Atklāj atmiņas noplūdes, datubāzes savienojumu leak, cache overflow, file descriptor iztrūkumu
- Spike test — pēkšņs slodzes pieaugums (0→max→0 ātri). Simulē vīrusu saturu vai mārketinga kampaņu. Pārbauda autoscaling ātrumu un sistēmas atjaunošanos
- Breakpoint test — mērķtiecīgs: palielina slodzi līdz atrod precīzu lūzuma punktu un cēloni
Reālistisks scenāriju dizains
Slodzes testi ar vienkāršu GET / pieprasījumu nav informatīvi. Reālistisks scenārijs:
- Lietotājs ienāk galvenajā lapā (GET /)
- Atver produktu sarakstu (GET /api/products)
- Skatās konkrētu produktu (GET /api/products/:id)
- Pievieno grozam (POST /api/cart)
- Aizpilda pasūtījuma formu (POST /api/checkout)
Katrs solis ar reālistisku think time (2–5s starp darbībām). Dažādi lietotāju ceļi ar svaru: 60% tikai pārlūko, 30% pievieno grozam, 10% pabeidz pirkumu.
Rīki — detalizēts salīdzinājums
k6 (Grafana Labs)
Moderns, JavaScript sintakse, izstrādātāju draudzīgs. Scenario-based testi ar VU (virtual user) modeli. Iebūvēts thresholds (tests fails automatizēti, ja metrikas pārsniedz robežu). Integrējas ar Grafana Cloud. Trūkumi: nav GUI, prasa JS zināšanas.
Artillery
YAML/JSON konfigurēts, vieglāks sākums. Iebūvēts Socket.io un GraphQL atbalsts. Piemērots API testēšanai. Trūkumi: mazāk elastīgs nekā k6 sarežģītiem scenārijiem.
autocannon
Vienkāršākais — CLI rīks ātrai HTTP slodžu testēšanai. Ideāls ātrai pārbaudei: `autocannon -c 100 -d 30 http://localhost:3000/api`. Nav piemērots sarežģītiem scenārijiem.
Gatling / JMeter
Enterprise rīki ar plašāku funkcionalitāti un GUI. Gatling (Scala) — ātrs, JMeter (Java) — plaši pielāgojams. Bieži pārmērs Node.js projektiem, bet piemēroti lieliem uzņēmumiem.
Galvenās metrikas — ko mērīt un kāpēc
Atbildes laiks (Latency)
- p50 (mediāna) — tipiskā pieredze. Ja p50 = 200ms, puse pieprasījumu ātrāki
- p95 — sliktākā "normālā" pieredze. 95% ātrāki par šo. Ja p95 = 1s, tas ir reālistisks sliktākais gadījums vairumam lietotāju
- p99 — tail latency. Ja p99 = 5s, 1% lietotāju pieredz ievērojamu lēnumu. Bieži norāda uz specifiskas problēmas
- Mērķi: p50 < 200ms, p95 < 500ms, p99 < 1s tipiskam API. Lapas ielāde: p50 < 1s, p95 < 3s
Caurlaidspēja (Throughput)
Pieprasījumi sekundē (RPS). Cik pieprasījumu sistēma apstrādā sekundē pie konkrētas slodzes. Vajadzētu lineāri augt ar VU skaitu — ja plateaus, ir bottleneck.
Kļūdu likme
% pieprasījumu, kas atgriež 5xx vai timeout. Mērķis: < 0.1% normālā slodzē. > 1% = kritiska problēma.
Resursu utilizācija
CPU, RAM, disk I/O, network I/O zem slodzes. Event loop delay (Node.js specifisks) — ja > 100ms, event loop ir bloķēts.
Biežas vājās vietas Node.js aplikācijās
Datubāzes vaicājumi — #1 bottleneck
- N+1 problēma — galvenais query + N papildu queries katram ierakstam. Risinājums: JOIN vai batch queries. Supabase: `.select('*, comments(*)')` eager loading
- Trūkstoši indeksi — EXPLAIN ANALYZE atklāj sequential scan uz lielas tabulas. Indekss uz bieži filtrētajām kolonnām: `CREATE INDEX idx_users_email ON users(email)`
- Connection pool iztrūkums — katrs pieprasījums veido jaunu savienojumu, nevis lieto pool. Supabase + pgbouncer; Prisma connection pool. Pool size: CPU cores × 2 + 1
- Neoptimizēti queries — SELECT * nevis SELECT vajadzīgās_kolonnas. Lieki dati tīklā = lēnāk
Event loop bloķēšana
Node.js ir single-threaded event loop. Sinhronas operācijas bloķē VISU:
- `JSON.parse()` ar lielu payload (>1MB) — bet async alternatīvas nepastāv; risinājums: worker thread
- `fs.readFileSync()` — vienmēr `fs.readFile()` vai `fs.promises.readFile()`
- CPU-intensīvi aprēķini — worker_threads vai atsevišķs microservice
- Smagas regex operācijas — ReDoS (regex denial of service). Testējiet regex ar safe-regex bibliotēku
Atmiņas noplūdes
- Neattīrīti event listeneri — `emitter.on()` bez `emitter.off()`. Max listeners warning ir simptoms
- Globāli augošie masīvi/Map — cache bez eviction politikas. Risinājums: LRU cache ar izmēra limitu
- Closures, kas saglabā atsauces uz lieliem objektiem
- Diagnostika: `--max-old-space-size` limits, heap snapshots ar Chrome DevTools, `process.memoryUsage()` monitorings
Optimizācijas stratēģijas
Kešošana — pareizi
- Redis — ārējais cache (in-memory). Piemērots: API atbilžu cache, sesijas, rate limiting dati. TTL: 5–60min atkarībā no datu mainīguma
- In-memory cache — `node-cache`, `lru-cache`. Piemērots: konfigurācija, retāk mainīgi dati. Uzmanīgi: nepastāvīgs (restart = zaudēts), katrai instancei savs
- CDN cache — statisks saturs un API atbilžu cache edge. Vercel/Cloudflare automātiski. `Cache-Control: s-maxage=60, stale-while-revalidate=300`
- Cache invalidation — grūtākā problēma. Event-driven invalidation (datubāzes trigger → Redis pub/sub → cache clear) vai TTL-based
Horizontāla mērogošana
- PM2 cluster mode — izmanto visus CPU kodolus. `pm2 start app.js -i max`
- Kubernetes HPA — automātiski pievieno/noņem pod balstoties uz CPU/memory metrikām
- Stateless dizains — sesijas Redis (ne in-memory), faili object storage (ne lokāli) — priekšnoteikums horizontālai mērogošanai
CI integrācija — automātisks gatekeeping
Slodzes testus integrējiet CI cauruļvadā:
- k6 ar thresholds: `http_req_duration: ['p95<500']` — tests fail, ja p95 > 500ms
- Automātiski noraidīt PR, ja veiktspēja pasliktinās virs noteikta sliekšņa
- Performance budgets: lapas svars, bundle izmērs, API atbildes laiks
- Baseline salīdzinājums: katru testu salīdzina ar iepriekšējo — trenda noteikšana
Biežāk uzdotie jautājumi
Cik bieži jāveic slodzes testi?
Minimāli: pirms katras lielas versijas un reizi mēnesī regulāri. Ideāli: k6 tests katrā CI pipeline ar automātiskiem thresholds. Soak testi — reizi kvartālā vai pirms sagaidāmām satiksmes virsotnēm (sezonas, kampaņas).
Kas ir p95 atbildes laiks?
95% pieprasījumu tiek apkalpoti ātrāk par šo laiku. Labāks rādītājs nekā vidējais, jo vidējais slēpj tail latency. Ja vidējais ir 200ms, bet p95 ir 3s — 5% lietotāju pieredz šausmīgu veiktspēju. Biežāk izmantojami benchmarks: p50 <200ms, p95 <500ms, p99 <1s.
Kurš rīks ir labākais iesācējiem?
k6 — moderna JavaScript sintakse, laba dokumentācija, bezmaksas lokālai lietošanai, viegli integrējams CI. Pamattestam pietiek ar 20 rindiņu skriptu. Artillery — ja priekšroka YAML konfigurācijai. autocannon — ātrāk vienkāršam HTTP benchmark.
Kā noteikt, vai problēma ir datubāzē vai kodā?
1) Monitorējiet event loop delay — ja > 50ms, kods bloķē event loop. 2) Datubāzes slow query log — EXPLAIN ANALYZE lēniem vaicājumiem. 3) APM rīks (NewRelic, DataDog) parāda laiku pa komponentiem. 4) Izolēti testi: testējiet API bez datubāzes (mokots) vs ar datubāzi.
Cik VU (virtual users) vajag testam?
Atkarīgs no sagaidāmās satiksmes. Formulas: pīķa stundu unikālie apmeklētāji × vidējais pieprasījumu skaits per apmeklētāju ÷ 3600 = RPS. Tad VU = RPS × vidējais atbildes laiks (s). Piemērs: 1000 lietotāji/h × 5 pieprasījumi ÷ 3600 = ~1.4 RPS × 0.3s = ~1 VU. Bet testējiet 3–5x virs sagaidāmā.