Mundarija (28)
- Bu darsda
- 1. Nega bu kerak?
- 2. To'rt xil test
- 3. Raqamlar: o'tkazuvchanlik va persentillar
- 3.1 Nega o'rtacha aldaydi
- 3.2 Little qonuni
- 4. O'zimiz o'lchab ko'ramiz
- 5. Kanon o'lchovi: 31-qism har so'rovga qancha qo'shdi
- 5.1 Usul
- 5.2 Natija
- 5.3 Natijani halol o'qish
- 6. To'yinish nuqtasi
- 6.1 Kanon chiqishi
- 6.2 Haqiqiy tizimdagi to'yinish: 429
- 7. Ssenariy va vositalar
- 7.1 Ochiq va yopiq model
- 7.2 k6
- 7.3 Prodakshnga o'xshash muhit
- 8. Sig'imni rejalash
- 9. Ko'p uchraydigan xatolar
- 10. Mashqlar
- 1-mashq (oson): bo'shliqlarni to'ldiring
- 2-mashq (o'rta): autocannon natijasidan hisobot
- 3-mashq (qiyin): to'yinish nuqtasini topish
- 11. Loyiha qadami: kanon o'lchovi
- 12. Real ishda
- Xulosa
- Manbalar
Yuklama va stress testlari: autocannon, k6, p99, to'yinish nuqtasi va sig'imni rejalash
Qisqacha: Yuklama testi (load test) — ilovaga bir vaqtda ko'p so'rov yuborib, u qancha so'rovni qancha vaqtda bajarishini o'lchash. Ikki asosiy raqam: o'tkazuvchanlik (throughput, soniyasiga so'rovlar — req/s) va kechikish (latency) — o'rtacha emas, persentil: p50, p95, p99. Ulanishlarni oshirib borsangiz, bir nuqtada o'tkazuvchanlik o'smay qoladi, kechikish esa o'sishda davom etadi — bu to'yinish nuqtasi (saturation). Kanon o'lchovida
vazifalar-apiro'yxat so'rovida ~2.5 ming req/s da to'yindi: 10 dan 200 ulanishgacha p99 10 ms dan 117 ms ga o'sdi, o'tkazuvchanlik deyarli o'zgarmadi. 31-qism qo'shgan qatlamlar (metrikalar, audit) har so'rovni 4–13 % sekinlashtirdi.
Bu darsda
- Load, stress, spike va soak testlarini farqlaysiz.
- Persentillarni hisoblaysiz va nega o'rtacha kechikish aldashini ko'rsatasiz.
- Little qonuni bilan ulanishlar, o'tkazuvchanlik va kechikishni bog'laysiz.
- Yuklama testini to'g'ri tashkil qilasiz: alohida jarayon, isitish, navbatma-navbat aylanalar, mediana.
- Kanon o'lchovini o'qib, to'yinish nuqtasini topasiz va sig'imni rejalashtirasiz.
Oldin bilishingiz kerak: Backend unumdorligini oshirish, Event loop'ni bloklash, Rate limiting, Contract va API sxema testlari.
1. Nega bu kerak?
Juma kuni IlmHamroh Telegram kanalida "vazifalar ilovasi" haqida post chiqdi. Bir soatda 3 000 kishi ro'yxatdan o'tdi va ilovani ochdi. Server bardosh beradimi?
"Funksional" testlar bu savolga javob bermaydi. 340 ta test har so'rovni bir marta yuboradi va "to'g'ri javob keldimi" deb tekshiradi. Yuklama testi boshqa savol beradi: bir vaqtda 200 ta so'rov kelsa, javob qancha vaqtda keladi? Qaysi nuqtada server "bo'g'iladi"? Bo'g'ilganda nima bo'ladi — sekinlashadimi, xato beradimi, yiqiladimi?
O'xshatish: ko'prik. Muhandis uning chizmasini tekshiradi (funksional test), lekin ochilishdan oldin unga tosh ortilgan yuk mashinalarini qo'yadi va egilishni o'lchaydi (yuklama testi). Chizma to'g'ri bo'lishi ko'prik 40 tonnani ko'tarishini kafolatlamaydi.
Backend unumdorligini oshirish darsida yuklama vositasini tor joy qidirish uchun ishlatdik. Bu darsda yuklama testining o'zini — usuli, raqamlari va tuzoqlarini — chuqur o'rganamiz.
2. To'rt xil test
| Test | Savol | Qanday |
|---|---|---|
| Load (yuklama) | kutilgan yukda me'yordamizmi? | kutilgan so'rovlar oqimi, 5–30 daqiqa |
| Stress | qayerda sinadi va qanday sinadi? | yukni sinishgacha oshirib borish |
| Spike (sakrash) | birdan 10× yuk kelsa? | bir lahzada katta yuk, keyin pasayish |
| Soak (uzoq muddatli) | soatlab ishlasa nima bo'ladi? | o'rtacha yuk, 4–24 soat |
Har biri boshqa xatoni topadi. Stress testi to'yinish nuqtasini va sinish shaklini ko'rsatadi: chiroyli sekinlashish yoki 500 lar quyuni. Spike — avtomatik masshtablash va ulanish hovuzlarining tezligini. Soak esa vaqt o'tib chiqadigan xatolarni: xotira oqishi, to'lib boradigan kesh, ochiq qolgan ulanishlar, disk to'lishi. 31-qism kanonida soak testi yo'q — u soatlab mashinani band qiladi va bitta kompyuterda o'tkazilgan o'lchov ishonchsiz bo'lardi.
3. Raqamlar: o'tkazuvchanlik va persentillar
3.1 Nega o'rtacha aldaydi
Backend unumdorligini oshirish darsida p50 va p99 ni ko'rgansiz. Endi ularni o'zimiz hisoblaymiz. 100 ta so'rov: 97 tasi 10 ms da, 3 tasi 400 ms da bajarildi (masalan, sovuq kesh yoki axlat yig'uvchi pauzasi):
function persentil(saralangan, p) {
const i = Math.ceil((p / 100) * saralangan.length) - 1;
return saralangan[Math.max(0, i)];
}
const vaqtlar = [...Array(97).fill(10), 400, 400, 400];
const s = vaqtlar.toSorted((a, b) => a - b);
const ortacha = vaqtlar.reduce((x, y) => x + y, 0) / vaqtlar.length;
console.log("o'rtacha:", ortacha.toFixed(1), "ms");
for (const p of [50, 95, 97, 98, 99]) {
console.log(`p${p}:`, persentil(s, p), "ms");
}Konsolda:
o'rtacha: 21.7 ms
p50: 10 ms
p95: 10 ms
p97: 10 ms
p98: 400 ms
p99: 400 msO'rtacha — 21.7 ms. Bunday so'rov bitta ham yo'q: 97 tasi ikki baravar tezroq, 3 tasi 18 baravar sekinroq. O'rtacha ikkala guruhni ham yashiradi. p50 "odatdagi foydalanuvchi nimani ko'radi" deydi, p99 — "eng omadsiz yuzdan biri".
Nega p99 muhim? Bitta sahifa ochilishida brauzer API'ga 5–10 ta so'rov yuboradi. Har biri 1 % ehtimol bilan sekin bo'lsa, 10 ta so'rovli sahifaning sekin ochilish ehtimoli — taxminan 10 %. Persentilni hisoblashda bir nechta usul bor; bu yerdagisi — "eng yaqin daraja" (nearest rank). Vositalar o'zaro biroz farq qilishi mumkin.
3.2 Little qonuni
Uchta raqam bir-biriga bog'liq. Little qonuni: tizimdagi o'rtacha so'rovlar soni = o'tkazuvchanlik × o'rtacha javob vaqti, ya'ni L = λ × W.
autocannon kabi vositalarda ulanishlar soni qat'iy: har ulanish javob olgach, darhol keyingi so'rovni yuboradi. Demak tizimda doim L = ulanishlar soni so'rov bor. Bundan: W = ulanishlar / o'tkazuvchanlik. Kanon o'lchovidagi raqamlar bilan tekshiramiz:
// Kanon o'lchovi: GET /v1/vazifalar?limit=20, 31-qism kanoni
const olchov = [
{ ulanish: 10, rps: 2283, p50: 3 },
{ ulanish: 50, rps: 2613, p50: 17 },
{ ulanish: 200, rps: 2478, p50: 76 },
];
for (const { ulanish, rps, p50 } of olchov) {
const w = (ulanish / rps) * 1000;
console.log(`${ulanish} ulanish: Little W = ${w.toFixed(1)} ms,` +
` o'lchangan p50 = ${p50} ms`);
}Konsolda:
10 ulanish: Little W = 4.4 ms, o'lchangan p50 = 3 ms
50 ulanish: Little W = 19.1 ms, o'lchangan p50 = 17 ms
200 ulanish: Little W = 80.7 ms, o'lchangan p50 = 76 msFormula o'rtacha vaqtni beradi, o'lchov esa medianani — o'rtacha medianadan biroz katta (sekin "dum" uni tortadi). Lekin tartib aniq mos. Asosiy xulosa: o'tkazuvchanlik to'yingandan keyin har qo'shimcha ulanish faqat kutish vaqtini oshiradi. 200 ulanishda server baribir ~2.5 ming req/s bajaradi — qolgan so'rovlar navbatda turadi.
Tekshirib ko'ring: Server to'yinish nuqtasida 2 500 req/s bajaradi. Unga 1 000 ulanish bilan yuk berilsa, o'rtacha javob vaqti taxminan qancha bo'ladi?
Javob
W = 1000 / 2500 = 0.4 s = 400 ms. Server tezlashmaydi — so'rovlar navbatda turadi. Haqiqatda undan ham yomon bo'lishi mumkin: navbat uzaygani sari xotira o'sadi, timeout'lar boshlanadi, mijozlar qayta urinadi — yuk o'z-o'zini kuchaytiradi (Resilience naqshlari darsidagi retry bo'roni).
4. O'zimiz o'lchab ko'ramiz
Nazariyani kichik tajribada tekshiramiz. Server har so'rovda 1 ms CPU ishini bajaradi (sikl bilan — Event loop'ni bloklash darsidagidek). Event loop bitta — demak soniyasiga ~1 000 so'rovdan ko'p bajara olmaydi. autocannon alohida jarayonda ishlaydi:
import { createServer } from "node:http";
import { execFile } from "node:child_process";
function ish(ms) {
const t = performance.now();
while (performance.now() - t < ms) { /* CPU band */ }
}
const server = createServer((req, res) => {
ish(1);
res.end("ok");
});
await new Promise((ok) => server.listen(5590, "127.0.0.1", ok));
const AC = "node_modules/autocannon/autocannon.js";
function yuk(ulanish, soniya) {
const args = [AC, "-c", String(ulanish), "-d", String(soniya),
"-j", "http://127.0.0.1:5590/"];
return new Promise((ok, rad) => execFile(process.execPath, args,
(x, out) => (x ? rad(x) : ok(JSON.parse(out)))));
}
await yuk(5, 1); // isitish
for (const c of [1, 10, 50]) {
const r = await yuk(c, 2);
console.log(`${String(c).padStart(2)} ulanish: ` +
`${Math.round(r.requests.average)} req/s, ` +
`p50 ${r.latency.p50} ms, p99 ${r.latency.p99} ms`);
}
server.close();Skript soddalashtirib ko'rsatilgan: AC — autocannon o'rnatilgan papkadagi fayl yo'li, bizning nusxamizda jadvalli chiqish uchun qo'shimcha tarmoq ham bor edi. Biz ishga tushirdik (autocannon 8.0.0, Node 24.21.0, bitta mashina, har bosqich 2 s; chiqishdan xatolar soni ustuni olib tashlangan — hammasi 0):
1 ulanish: 640 req/s, p50 1 ms, p99 2 ms
10 ulanish: 770 req/s, p50 12 ms, p99 18 ms
50 ulanish: 648 req/s, p50 67 ms, p99 189 msBitta ulanishda server bo'sh turgan paytlari bor: javob mijozga borib, keyingi so'rov kelguncha. 10 ulanishda u to'liq band — o'tkazuvchanlik eng yuqori. 50 ulanishda o'tkazuvchanlik oshmadi (hatto pasaydi — ko'p ulanishni boshqarish ham CPU oladi), p50 esa 67 ms ga chiqdi. Little: 50 / 648 ≈ 77 ms. O'lchov 2 soniyalik, bitta yugurish — raqamlar har safar biroz boshqacha bo'ladi, shakli esa yo'q.
autocannon jadvalli chiqishi ham shuni ko'rsatadi (10 ulanish, 2 s):
Running 2s test @ http://127.0.0.1:5590/
10 connections
┌─────────┬──────┬───────┬───────┬───────┬──────────┬─────────┬───────┐
│ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │
├─────────┼──────┼───────┼───────┼───────┼──────────┼─────────┼───────┤
│ Latency │ 6 ms │ 12 ms │ 18 ms │ 20 ms │ 12.14 ms │ 2.59 ms │ 24 ms │
└─────────┴──────┴───────┴───────┴───────┴──────────┴─────────┴───────┘
┌───────────┬───────┬───────┬───────┬─────────┬─────────┬───────┬───────┐
│ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │
├───────────┼───────┼───────┼───────┼─────────┼─────────┼───────┼───────┤
│ Req/Sec │ 782 │ 782 │ 782 │ 792 │ 787 │ 5 │ 782 │
├───────────┼───────┼───────┼───────┼─────────┼─────────┼───────┼───────┤
│ Bytes/Sec │ 97 kB │ 97 kB │ 97 kB │ 98.2 kB │ 97.6 kB │ 608 B │ 97 kB │
└───────────┴───────┴───────┴───────┴─────────┴─────────┴───────┴───────┘
Req/Bytes counts sampled once per second.
# of samples: 2
2k requests in 2.01s, 195 kB readYuqori jadval — kechikish persentillari, pastki — soniyalik o'tkazuvchanlik. # of samples: 2 ga e'tibor bering: o'tkazuvchanlik har soniyada bir marta o'lchanadi, 2 soniyali test atigi 2 ta nuqta beradi. Ishonchli raqam uchun uzoqroq test kerak.
5. Kanon o'lchovi: 31-qism har so'rovga qancha qo'shdi
5.1 Usul
31-qismda vazifalar-api ga ko'p narsa qo'shildi: Prometheus metrikalari (har so'rovda vaqt o'lchanadi), global audit interceptor, feature flag'lar. Ular har so'rovga qancha narx qo'shdi? Kanon 30-qism oxiridagi va 31-qism oxiridagi ilovani bir vaqtda, bir xil sozlama bilan ishga tushirdi (xotira ombori, auth'siz, cheklovsiz) va solishtirdi.
Usul 30-qismdagi yordamchidan olingan va uning har qadami bitta xatoning oldini oladi:
| Qadam | Nega |
|---|---|
| autocannon alohida jarayonda | server bilan bitta event loop'da yuk beruvchi o'zi "tor joy" bo'lib qoladi |
| 1 s isitish | birinchi so'rovlar JIT kompilyatsiyasi va keshlarni to'ldiradi |
| 5 aylana × 3 s, variantlar navbatma-navbat | mashina yuki o'zgarsa, ikkala variantga teng tushadi |
| mediana va oraliq | bitta omadli yoki omadsiz aylana natijani buzmasin |
5.2 Natija
Har so'rov uchun ikki qator bor: yuqorisi — 30-qism oxiri, pastkisi — 31-qism oxiri. Medianani va qavs ichidagi oraliqni birga o'qing. Kanon chiqishi (2026-11-03, Node 24.21.0, bitta mashina — o'yin va boshqa jarayonlar bilan band):
GET /v1/vazifalar?limit=20
30-qism oxiri: mediana 2552 req/s (oraliq 2066–2860), p50 3 ms, p99 10 ms, xato 0
31-qism oxiri: mediana 2224 req/s (oraliq 1657–2394), p50 3 ms, p99 12 ms, xato 0
GET /v1/vazifalar/1
30-qism oxiri: mediana 3280 req/s (oraliq 3142–3394), p50 2 ms, p99 8 ms, xato 0
31-qism oxiri: mediana 3045 req/s (oraliq 2998–3348), p50 2 ms, p99 9 ms, xato 0
GET /v1/teglar
30-qism oxiri: mediana 3844 req/s (oraliq 3496–4193), p50 2 ms, p99 7 ms, xato 0
31-qism oxiri: mediana 3653 req/s (oraliq 3376–3822), p50 2 ms, p99 8 ms, xato 0
PATCH /v1/vazifalar/1 {"bajarildi":true}
30-qism oxiri: mediana 2570 req/s (oraliq 2235–2662), p50 3 ms, p99 12 ms, xato 0
31-qism oxiri: mediana 2460 req/s (oraliq 2180–2542), p50 3 ms, p99 12 ms, xato 0"30-qism oxiri" — 30-qism yakunidagi loyiha, "31-qism oxiri" — shu darslardagi yakuniy loyiha (yorliqlar qisqartirilgan). Grafikda — 31-qism o'tkazuvchanligi 30-qismnikiga nisbatan:
- GET ro'yxat87 %
- GET bitta93 %
- GET teglar95 %
- PATCH96 %
Manba: IlmHamroh kanon o'lchovi, 2026-11-03: autocannon, 5 aylana × 3 s mediana; 30 va 31 kanonlari bir vaqtda, xotira ombori; bitta mashina, band
5.3 Natijani halol o'qish
Farq bor, lekin kichik. Ro'yxat so'rovida −13 %, qolganlarida −4…−7 %. p99 deyarli o'zgarmadi (10 → 12 ms).
Oraliqlar ustma-ust tushadi. Ro'yxatda 30-qism 2 066–2 860, 31-qism 1 657–2 394. 31-qismning eng yaxshi aylanasi 30-qismning ko'p aylanasidan tezroq. Shuning uchun "−13 %" ni aniq raqam emas, yo'nalish sifatida o'qing: 31-qism biroz sekinroq. Mashina o'lchov paytida band edi — mutlaq req/s ni boshqa kompyuterga ko'chirib bo'lmaydi.
Sabab — taxmin. Kanon har so'rovdagi uchta yangi ishni ko'rsatadi: metrikalar middleware'i (vaqt o'lchash va finish hodisasi), global AuditInterceptor (har so'rovda belgini o'qiydi, yozuv faqat belgilangan amallarda), Problem sarlavhalari. Ularning har biri alohida o'lchanmagan. Aniq javob kerak bo'lsa — profil (CPU profiling va flamegraph) yoki bittalab o'chirib o'lchash.
Narx arzimi? 4–13 % evaziga loyiha har so'rovning metrikasini, admin amallarining o'zgarmas jurnalini oldi. Ro'yxat so'rovi baribir 3 ms (p50) da javob beradi — foydalanuvchi farqni sezmaydi. Bu — muhandislik qarori, o'lchov esa uni ongli qiladi.
6. To'yinish nuqtasi
6.1 Kanon chiqishi
Kanon 31-qism ilovasiga ro'yxat so'rovida ulanishlarni oshirib bordi (har bosqich 5 s). Qatordan qatorga req/s qanchalik o'zgarganini va p99 qanchalik o'zgarganini alohida kuzating:
saturatsiya (31, GET /v1/vazifalar?limit=20, 5 s):
10 ulanish: 2283 req/s, p50 3 ms, p99 10 ms, xato 0
50 ulanish: 2613 req/s, p50 17 ms, p99 40 ms, xato 0
200 ulanish: 2478 req/s, p50 76 ms, p99 117 ms, xato 0O'tkazuvchanlik (bitta yugurish, mutlaq qiymat):
| ulanishlar | req/s |
|---|---|
| 10 | 2 283 |
| 50 | 2 613 |
| 200 | 2 478 |
Manba: IlmHamroh kanon o'lchovi, 2026-11-03: autocannon, har nuqta 5 s, bitta yugurish; xotira ombori; bitta mashina, band
10 dan 50 ga — o'tkazuvchanlik +14 %, p99 4 baravar. 50 dan 200 ga — o'tkazuvchanlik o'smadi, p99 yana 3 baravar. To'yinish nuqtasi — taxminan 2.5 ming req/s, 10–50 ulanish oralig'ida. Undan keyin server ko'proq ish qilmaydi, faqat ko'proq kutdiradi.
Bu grafik ko'pincha "tirsak" (knee) shaklida chiziladi: avval chiziq tik ko'tariladi, keyin gorizontal yotadi. Kechikish grafigi esa teskari: avval tekis, tirsakdan keyin keskin yuqoriga.
6.2 Haqiqiy tizimdagi to'yinish: 429
Yuqoridagi o'lchov — xotira omborida, auth'siz. Haqiqiy rejimda (Postgres, sessiya bilan) kanon Backend unumdorligini oshirish darsida boshqa narsani ko'rgan edi. O'sha qatorni eslang (yorliqlar qisqartirilgan):
2026-11-03T10:54:07+05:00 | asos | SAQLASH=postgres LOG_LEVEL=info | 838 req/s, p50 22 ms, p99 38 ms, kodlar 429×12569, xatolar 0Barcha javob — 429. Yuklama testi bitta foydalanuvchi (Aziz) sessiyasi bilan yuborildi, Rate limiting esa bitta foydalanuvchiga daqiqasiga 600 so'rov beradi. Test API'ni emas, cheklagichni o'lchadi. xatolar 0 ham aldaydi: autocannon tarmoq xatolarini sanaydi, 429 esa to'g'ri HTTP javob.
Saboq: ssenariy haqiqatga o'xshashi kerak. Haqiqiy yukda minglab foydalanuvchi bor, har birining o'z sessiyasi. Yuklama testida ham: ko'p test foydalanuvchisi (oldindan yaratilgan, sessiyalari bilan) yoki test muhitida cheklov chegarasini oshirish. Javob kodlarini doim tekshiring — "tez" javob ko'pincha "tez rad".
Tekshirib ko'ring: Yuklama testida 5 000 req/s chiqdi, p99 — 2 ms. Hamkasbingiz "server juda tez!" deydi. Nimani birinchi tekshirasiz?
Javob
Javob kodlarini. 429 (cheklov), 401 (sessiya tugagan), 404 (noto'g'ri URL) yoki 304 (kesh) — hammasi tez va "xatosiz". Keyin — javob tanasi haqiqiy ishni ko'rsatadimi (bo'sh ro'yxat ham tez). Kanon aynan shu tuzoqqa tushgan: hamma javob 429 edi.
7. Ssenariy va vositalar
7.1 Ochiq va yopiq model
autocannon — yopiq model (closed model): N ulanish, har biri javob olgach keyingi so'rovni yuboradi. Server sekinlashsa, yuk ham avtomatik kamayadi. Haqiqiy foydalanuvchilar esa serverni kutib o'tirmaydi — ular o'z vaqtida keladi: ochiq model (open model), "soniyasiga 500 ta yangi so'rov" deb beriladi.
Farq muhim. Yopiq modelda server bir zum qotib qolsa, yuk beruvchi ham to'xtaydi va o'sha paytdagi kechikishlar o'lchovga tushmaydi — muvofiqlashgan e'tiborsizlik (coordinated omission). Natijada p99 haqiqatdagidan chiroyliroq chiqadi. Ochiq model buni ko'rsatadi: kutilmagan so'rovlar navbati o'sadi va kechikishga yoziladi.
7.2 k6
k6 — Grafana'ning yuklama vositasi: ssenariy JavaScript'da yoziladi, dvigatel esa Go'da (Node emas — import lar k6 ning o'z modullari). Ochiq modelni ham qo'llaydi. Quyidagi ssenariy rasmiy hujjat bo'yicha yozilgan, kanonda sinalmagan (2026-11):
import http from "k6/http";
import { check } from "k6";
export const options = {
scenarios: {
royxat: {
executor: "constant-arrival-rate", // ochiq model
rate: 500, timeUnit: "1s", // soniyasiga 500 so'rov
duration: "2m",
preAllocatedVUs: 50, maxVUs: 200,
},
},
thresholds: {
http_req_duration: ["p(99)<100"], // p99 < 100 ms
http_req_failed: ["rate<0.01"], // xato < 1 %
},
};
export default function () {
const r = http.get("http://127.0.0.1:3000/v1/vazifalar?limit=20", {
headers: { Cookie: `__Host-sessiya=${__ENV.SESSIYA}` },
});
check(r, { "200": (x) => x.status === 200 });
}autocannon'da uch narsa yo'q. Birinchisi — ochiq model (constant-arrival-rate). Ikkinchisi — chegaralar (thresholds — p99 100 ms dan oshsa, k6 nol bo'lmagan kod bilan chiqadi, ya'ni CI'da test "yiqiladi"). Uchinchisi — tekshiruv (check — status kodini tekshiradi; 429 tuzog'iga qarshi). Ko'p foydalanuvchi uchun sessiyalar ro'yxatini fayldan o'qish mumkin.
Artillery — YAML'da ssenariy, Node'da ishlaydi; foydalanuvchi "sayohati" (kirish → ro'yxat → qo'shish) uchun qulay. U ham sinalmagan.
| Vosita | Ssenariy | Model | Kanonda |
|---|---|---|---|
| autocannon | CLI bayroqlari yoki Node API | yopiq | bor (25-qismdan) |
| k6 | JavaScript (Go dvigateli) | ochiq va yopiq | sinalmagan |
| Artillery | YAML + JS | ochiq | sinalmagan |
7.3 Prodakshnga o'xshash muhit
Yuklama testi faqat muhit o'xshash bo'lsa ma'noli. Kanon o'lchovi bunga javob bermaydi — u ataylab soddalashtirilgan (xotira ombori, bitta kompyuter). Haqiqiy reja uchun:
| Jihat | Nima bo'lishi kerak |
|---|---|
| Yuk beruvchi | alohida mashinada (server CPU'sini yemasin) |
| Ma'lumot hajmi | prodakshndagidek: 10 qatorli va 10 million qatorli jadval — boshqa so'rov rejalari (26-qismdagi EXPLAIN) |
| Sozlama | o'sha NODE_ENV, log darajasi, ulanish hovuzi o'lchami |
| Foydalanuvchilar | ko'p sessiya; cheklov — prodakshndagidek yoki ataylab oshirilgan |
| Tashqi xizmatlar | AI, email, to'lov — soxta (simulyator); haqiqiysiga yuklama yubormang |
Oxirgi qator jiddiy. Yuklama testi AI provayderiga 10 000 so'rov yuborsa — bu hisob-faktura. Kanon testlari haqiqiy Gemini'ga bormaydi: soxta provayder ishlaydi.
8. Sig'imni rejalash
Yuklama testining amaliy maqsadi — "nechta server kerak?" degan savolga javob. Oddiy hisob:
function serverlar({ choqqi, toyinish, ulush = 0.7 }) {
// to'yinishning 70 % igacha yuklaymiz — 30 % bo'sh joy
return Math.ceil(choqqi / (toyinish * ulush));
}
const toyinish = 2500; // kanon: GET ro'yxat, bitta jarayon
for (const choqqi of [300, 2000, 6000]) {
console.log(`cho'qqi ${choqqi} req/s →`,
serverlar({ choqqi, toyinish }), "ta jarayon");
}Konsolda:
cho'qqi 300 req/s → 1 ta jarayon
cho'qqi 2000 req/s → 2 ta jarayon
cho'qqi 6000 req/s → 4 ta jarayonNega 70 %? To'yinish nuqtasi yaqinida kechikish keskin o'sadi (Little), va bitta jarayon yiqilsa, qolganlari uning yukini olishi kerak. "Cho'qqi" esa o'rtacha emas: 3 000 kishi bir soatda — o'rtacha 1 kishi/s, lekin post chiqqan dastlabki 5 daqiqada ularning yarmi keladi.
Bu hisob soddalashtirilgan: u faqat bitta so'rov turini va bitta Node jarayonini oladi. Haqiqatda tor joy ko'pincha Node emas — ma'lumotlar bazasi ulanishlari yoki tashqi xizmat. Ko'p yadroli serverda bir nechta jarayon (cluster) va ularni ko'tarish — 33-qism mavzusi.
9. Ko'p uchraydigan xatolar
| Xato | Oqibati | To'g'risi |
|---|---|---|
| O'rtacha kechikishga qarash | sekin "dum" ko'rinmaydi | p50, p95, p99 |
| Yuk beruvchi server bilan bitta jarayonda | yuk beruvchi o'zi tor joy | alohida jarayon yoki mashina |
| Bitta foydalanuvchi sessiyasi bilan test | cheklagich o'lchanadi (429) | ko'p sessiya; javob kodlarini tekshirish |
| Isitishsiz bitta qisqa yugurish | JIT va kesh natijani buzadi | isitish, bir necha aylana, mediana |
| Noutbukdagi raqamni prodakshnga ko'chirish | sig'im noto'g'ri baholanadi | nisbat va shakl; prodakshnga o'xshash muhit |
| Haqiqiy tashqi xizmatga yuklama | pul, bloklanish | soxta provayder |
| Faqat yopiq model | coordinated omission — p99 chiroyli chiqadi | ochiq model (k6 arrival-rate) |
10. Mashqlar
Mashqlar kurs/mashqlar/31/33-yuklama/ da. 2- va 3-mashq yechimlari Node 24.21.0 da tekshirilgan (biz ishga tushirdik).
1-mashq (oson): bo'shliqlarni to'ldiring
- Soatlab o'rtacha yuk bilan xotira oqishini qidiruvchi test — test.
- Little qonuni: L = λ ×
- Kanon o'lchovida 31-qism ro'yxat so'rovi o'tkazuvchanligi 30-qismdan taxminan % past chiqdi.
- autocannon ishlatadigan model — model.
- Bitta foydalanuvchi bilan yuklama testida kanon hamma javobda kodini oldi.
Yechim
- soak — uzoq muddatli test; 31-qism kanonida yo'q.
- W — o'rtacha javob vaqti; L — tizimdagi so'rovlar, λ — o'tkazuvchanlik.
- 13 — 2 552 dan 2 224 req/s ga (oraliqlar ustma-ust).
- yopiq — N ulanish, javobdan keyin keyingi so'rov.
- 429 — cheklov: bitta foydalanuvchiga daqiqasiga 600 so'rov.
2-mashq (o'rta): autocannon natijasidan hisobot
autocannon -j (JSON) chiqishidan qisqa hisobot yasaydigan hisobot(r) funksiyasini yozing: o'tkazuvchanlik (butun songa yaxlitlangan), p50 va p99, muvaffaqiyatli javoblar ulushi (non2xx ham xato). Agar 2xx bo'lmagan javoblar 1 % dan ko'p bo'lsa, oxiriga "OGOH: 2xx bo'lmagan javoblar" qo'shing. Namuna ma'lumot autocannon chiqishi tuzilmasida berilgan. Ishora: toFixed, shablon satr.
Yechim
function hisobot(r) {
const jami = r.requests.total;
const yomon = r.errors + r.non2xx;
const ulush = ((jami - yomon) / jami) * 100;
let s = `${Math.round(r.requests.average)} req/s, ` +
`p50 ${r.latency.p50} ms, p99 ${r.latency.p99} ms, ` +
`muvaffaqiyat ${ulush.toFixed(1)} %`;
if (r.non2xx / jami > 0.01) s += " | OGOH: 2xx bo'lmagan javoblar";
return s;
}
const tez = {
requests: { average: 838.4, total: 25152 },
latency: { p50: 22, p99: 38 },
errors: 0, non2xx: 25152,
};
const sog = {
requests: { average: 2283.2, total: 11416 },
latency: { p50: 3, p99: 10 },
errors: 0, non2xx: 0,
};
console.log(hisobot(sog));
console.log(hisobot(tez));Konsolda:
2283 req/s, p50 3 ms, p99 10 ms, muvaffaqiyat 100.0 %
838 req/s, p50 22 ms, p99 38 ms, muvaffaqiyat 0.0 % | OGOH: 2xx bo'lmagan javoblarIkkinchi namuna kanonning 429 holatiga o'xshatib yasalgan: hamma javob 2xx emas. errors: 0 bo'lsa ham, muvaffaqiyat 0 % — hisobot buni birinchi qatorda ko'rsatadi. Namunadagi total raqamlari o'ylab topilgan (tuzilma uchun); req/s, p50 va p99 — kanon o'lchovidan.
3-mashq (qiyin): to'yinish nuqtasini topish
Ulanishlar oshirilgan o'lchovlar ro'yxati berilgan. toyinish(olchov) funksiyasini yozing: keyingi bosqichda o'tkazuvchanlik 10 % dan kam o'sgan, p99 esa 50 % dan ko'p o'sgan birinchi nuqtani qaytarsin (bu — to'yinish boshlangan joy). Bunday nuqta bo'lmasa — null. Kanon ma'lumoti va o'zingizning kichik tajribangiz natijasida sinang. Ishora: for sikl va qo'shni elementlar (massivning HOF metodlari ham mumkin).
Yechim
function toyinish(olchov) {
for (let i = 0; i + 1 < olchov.length; i++) {
const [a, b] = [olchov[i], olchov[i + 1]];
const rpsOsish = b.rps / a.rps - 1;
const p99Osish = b.p99 / a.p99 - 1;
if (rpsOsish < 0.1 && p99Osish > 0.5) {
return { ulanish: a.ulanish, rps: a.rps, p99: a.p99 };
}
}
return null;
}
const kanon = [
{ ulanish: 10, rps: 2283, p99: 10 },
{ ulanish: 50, rps: 2613, p99: 40 },
{ ulanish: 200, rps: 2478, p99: 117 },
];
const tajriba = [
{ ulanish: 1, rps: 640, p99: 2 },
{ ulanish: 10, rps: 770, p99: 18 },
{ ulanish: 50, rps: 648, p99: 189 },
];
console.log("kanon:", toyinish(kanon));
console.log("1 ms CPU server:", toyinish(tajriba));
console.log("to'yinmagan:", toyinish(kanon.slice(0, 2)));Konsolda:
kanon: { ulanish: 50, rps: 2613, p99: 40 }
1 ms CPU server: { ulanish: 10, rps: 770, p99: 18 }
to'yinmagan: nullKanonda 10 → 50 o'tishida o'tkazuvchanlik hali 14 % o'sdi — bu to'yinish emas. 50 → 200 da o'smadi, p99 esa uch baravar — nuqta 50 ulanishda. "To'yinmagan" qatorda 10 → 50 o'tishi 10 % dan ko'p o'sdi, demak oxirgi nuqtagacha to'yinish ko'rinmadi — ulanishlarni yana oshirish kerak. Chegaralar (10 % va 50 %) — kelishuv, qonun emas.
11. Loyiha qadami: kanon o'lchovi
Bu darsda vazifalar-api kodi o'zgarmaydi — yuklama testi kanonda alohida tajriba sifatida qilindi va loyihaga fayl qo'shmadi. Natijalar yuqorida: 31-qism qatlamlari narxi va to'yinish nuqtasi.
O'zingiz takrorlay olasiz (Docker'siz, xotira omborida). Avval loyihani yig'ing va ishga tushiring:
npm run build
SAQLASH=xotira EGASI_ID=1 LOG_LEVEL=warn \
CORS_ORIGINS=http://localhost:5173 PORT=3000 node dist/main.jsBu — kanon o'lchovidagi sozlama. SAQLASH=xotira va EGASI_ID=1 — 30-qismdagi auth'siz xotira rejimi: cheklov ham, baza ham yo'q, faqat ilova kodi o'lchanadi. LOG_LEVEL=warn — har so'rov logga yozilmasin. Boshqa terminalda bir nechta vazifa qo'shing va yuk bering:
for i in 1 2 3 4 5; do
curl -s -X POST -H "Content-Type: application/json" \
-d "{\"matn\":\"Yuklama vazifasi $i\"}" \
http://127.0.0.1:3000/v1/vazifalar > /dev/null
done
URL="http://127.0.0.1:3000/v1/vazifalar?limit=20"
npx autocannon -c 10 -d 5 "$URL"
npx autocannon -c 50 -d 5 "$URL"Natijangiz kanondan boshqacha bo'ladi — kompyuteringiz boshqa. Mutlaq req/s ni emas, shaklni solishtiring: 10 dan 50 ulanishga o'tishda o'tkazuvchanlik qancha o'sdi, p99 necha baravar. Agar -c 200 ham sinasangiz — to'yinish nuqtangizni topasiz. Javob kodlariga qarang: 2xx dan boshqa javoblar bo'lsa, autocannon ularning sonini jadval ostida alohida aytadi — «Haqiqiy tizimdagi to'yinish: 429» bo'limidagi tuzoqni eslang.
Hali commit qilmang — loyihaning yakuniy bosqichi keyingi darsda tugaydi: test arxitekturasi, CI fayli va commit.
12. Real ishda
- Qayerda uchraydi: katta aksiya, reklama, imtihon kuni ro'yxatdan o'tish oldidan — "Qora juma" ga tayyorgarlik har elektron do'konda yuklama testidan boshlanadi. Infratuzilmani o'zgartirgandan keyin ham (yangi server turi, yangi Postgres versiyasi).
- Vositalar: k6 (Grafana k6 Cloud), Artillery, autocannon, Gatling, JMeter, Locust; natijalar — Prometheus va Grafana'da (Observability). SLO: "p99 < 300 ms, 99.9 % so'rovlar" — yuklama testining chegaralari shundan olinadi.
- Intervyu savollari: "p99 nima va nega o'rtacha emas?", "Throughput va latency qanday bog'langan?", "Load, stress va soak testining farqi?", "Yuklama testi natijasiga qanday ishonasiz?", "Coordinated omission nima?"
Xulosa
- Yuklama testi bir vaqtdagi yukda o'tkazuvchanlik va kechikishni o'lchaydi; load, stress, spike va soak — turli savollarga javob.
- O'rtacha kechikish aldaydi — p50, p95, p99 ga qarang; Little qonuni: W = ulanishlar / o'tkazuvchanlik.
- To'yinishdan keyin o'tkazuvchanlik o'smaydi, faqat kutish o'sadi: kanonda ~2.5 ming req/s, p99 10 → 117 ms.
- 31-qism qatlamlari har so'rovni 4–13 % sekinlashtirdi — bitta band mashinada, oraliqlar ustma-ust: yo'nalish, aniq raqam emas.
- Ssenariy haqiqatga o'xshasin: ko'p sessiya, javob kodlari tekshiriladi — aks holda cheklagich o'lchanadi (429).
- Sig'im: cho'qqi yuk / (to'yinish × 0.7) — keyin prodakshnga o'xshash muhitda tekshiriladi.
Keyingi dars: Test arxitekturasi va CI — 340 ta testni tez va barqaror qilish: parallellik, beqaror testlar, lokal check, CI fayli va 31-qismning yakuniy commit'i.
Manbalar
- autocannon — README (bayroqlar, JSON chiqishi): https://github.com/mcollina/autocannon (sinalmagan URL, 2026-11)
- Grafana k6 hujjati — Open and closed models: https://grafana.com/docs/k6/latest/using-k6/scenarios/concepts/open-vs-closed/ (sinalmagan, 2026-11)
- Grafana k6 hujjati — Thresholds: https://grafana.com/docs/k6/latest/using-k6/thresholds/ (sinalmagan, 2026-11)
- Grafana k6 hujjati — Load test types: https://grafana.com/docs/k6/latest/testing-guides/test-types/ (sinalmagan, 2026-11)
- Artillery hujjati: https://www.artillery.io/docs (sinalmagan, 2026-11)
- Google SRE Book — Monitoring Distributed Systems (persentillar): https://sre.google/sre-book/monitoring-distributed-systems/ (sinalmagan URL, 2026-11)
- Gil Tene — "How NOT to Measure Latency" (coordinated omission), ma'ruza: https://www.youtube.com/watch?v=lJ8ydIuPFeU (sinalmagan URL, 2026-11)
- Kanon o'lchovi (IlmHamroh, 2026-11-03): 30 va 31 kanonlari solishtiruvi va to'yinish (autocannon 8.0.0, xotira ombori), Postgres rejimidagi 429 o'lchovi. Bitta mashina, band.
- Biz ishga tushirdik (2026-11-03, autocannon 8.0.0, Node 24.21.0): 1 ms CPU server tajribasi. Brauzer modellari va mashqlar — Node 24.21.0.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!