QA 23: Performance testing — Load, Stress, Spike, Soak va k6 bilan amaliyot
🧪 QA Engineer — Zero to Hero
QA 23: Performance testing — Load, Stress, Spike, Soak va k6 bilan amaliyot
Holat: 2026-yil oktabr. Dars Grafana k6 ning v2 qatori (eng so'nggi reliz — v2.3.0, 2026-yil 21-sentabr) va rasmiy k6 hujjatlari asosida yozilgan. Amaliy nishon — Grafana'ning o'quv ilovasi QuickPizza. Barcha raqamli chegaralar (Core Web Vitals, Apdex) manbalar bilan berilgan.
Bu darsdan keyin siz: performance testni "tugmani bosib RPS'ni ko'rish" emas, balki muhandislik jarayoni sifatida bajara olasiz:
- latency, percentile (p95/p99), throughput va xato ulushini to'g'ri o'qiysiz;
- smoke, load, stress, spike, soak va breakpoint testlarini farqlab, vaziyatga mosini tanlaysiz;
- k6'da
stages,thresholds,scenarios, custom metrikalar va test data bilan skript yozasiz; - natijani tahlil qilib, jamoaga tushunarli hisobot yozasiz;
- frontend (Core Web Vitals) va mobil performance asoslarini bilasiz.
Mundarija
- Performance testing nima va nega kerak
- Asosiy metrikalar: latency, percentile, throughput, xatolar
- Little's Law va Apdex
- Test turlari: smoke, load, stress, spike, soak, breakpoint
- Jarayon: SLO'dan hisobotgacha
- k6 bilan tanishuv: o'rnatish va birinchi skript
- k6 chuqurroq: checks, thresholds, scenarios, metrikalar, data
- Natijani o'qish, hisobot va CI
- Boshqa vositalar: JMeter, Gatling, Locust
- Frontend va mobil performance
- Etika va xavfsizlik qoidalari
- Amaliy mashqlar
- O'zingizni tekshiring
- Xulosa
- Manbalar
1. Performance testing nima va nega kerak {#nima-uchun}
Performance testing — tizim yuklama ostida qanchalik tez, barqaror va kengayuvchan (scalable) ishlashini tekshiradigan non-functional testlash turi. Funksional test "ishlaydimi?" deb so'raydi, performance test esa "ko'p odam bir vaqtda ishlatganda ham yetarlicha tez va xatosiz ishlaydimi?" deb so'raydi.
| Savol turi | Funksional test | Performance test |
|---|---|---|
| Misol | "Buyurtma berish tugmasi buyurtma yaratadimi?" | "Bir daqiqada 600 ta buyurtma kelsa, 95% so'rov 1 soniyadan tez javob oladimi?" |
| Natija | O'tdi / O'tmadi | Raqamlar: p95, RPS, xato ulushi, CPU, xotira |
| Qayerda | Har qanday muhit | Prod'ga o'xshash, alohida muhit |
DemoBozor misoli. Aksiya kuni soat 20:00 da barcha mijozlarga push yuboriladi: "Choynaklarga −30%". 2–3 daqiqa ichida trafik odatdagidan bir necha baravar oshadi. Nima sinishi mumkin?
- ma'lumotlar bazasi ulanishlari (connection pool) tugab qoladi →
500va503xatolar; - kesh bo'sh bo'lsa, hamma so'rov bir vaqtda bazaga uriladi (cache stampede);
- SMS (OTP) xizmati sekundiga cheklangan miqdordagi xabarni qabul qiladi → login "osilib" qoladi;
- to'lov provayderiga so'rovlar timeout bo'ladi → buyurtma
PENDING_PAYMENTholatida qotib qoladi.
Bularni funksional testlar topmaydi — har bir so'rov alohida olinganda "to'g'ri" ishlaydi.
QA'ning roli. Performance testni ko'pincha QA, DevOps/SRE va dasturchilar birga qiladi. QA odatda: talablarni (NFR — non-functional requirements) aniqlashtiradi, yuklama modelini loyihalaydi, skript yozadi, natijani tahlil qilib hisobot beradi. Server ichidagi sababni topish (profiling) — ko'proq dasturchi/SRE ishi.
🎯 Intervyuda: Load test va stress test farqi nima? — Load test kutilgan (o'rtacha yoki cho'qqi) yuklamada SLO bajarilishini tekshiradi; stress test yuklamani kutilganidan yuqoriga olib chiqib, tizim qayerda va qanday buzilishini hamda keyin tiklanishini o'rganadi.
2. Asosiy metrikalar: latency, percentile, throughput, xatolar {#metrikalar}
Response time (latency) qanday tuzilgan
Bitta HTTP so'rov vaqti bir necha bo'lakdan iborat. k6 ularning har birini alohida o'lchaydi:
| Bosqich | k6 metrikasi | Ma'nosi |
|---|---|---|
| Navbatda kutish | http_req_blocked | Bo'sh TCP ulanish kutilgan vaqt |
| TCP ulanish | http_req_connecting | Serverga ulanish |
| TLS | http_req_tls_handshaking | HTTPS "qo'l berib ko'rishish" |
| Yuborish | http_req_sending | So'rov tanasini yuborish |
| Kutish (TTFB) | http_req_waiting | Server javobining birinchi baytigacha |
| Qabul qilish | http_req_receiving | Javobni to'liq yuklab olish |
| Jami | http_req_duration | sending + waiting + receiving (DNS va ulanishsiz) |
🧠 Esda tuting:
http_req_waiting(TTFB) katta bo'lsa — muammo odatda serverda (kod, baza, tashqi servis).http_req_receivingkatta bo'lsa — javob juda og'ir (masalan, siqilmagan 5 MB JSON) yoki tarmoq sekin.
O'rtacha qiymat nega aldaydi: percentile'lar
10 ta so'rov javob vaqti (ms): 120, 130, 125, 140, 135, 128, 132, 3000, 138, 127.
- O'rtacha (avg) = 4175 / 10 = 417.5 ms. Lekin hech bir foydalanuvchi 417 ms ni ko'rmadi: 9 kishi ~130 ms, bittasi esa 3 soniya kutdi.
- Mediana (p50) = 131 ms — "odatiy" foydalanuvchi tajribasi.
- p95 — so'rovlarning 95% shu qiymatdan tez. Ko'p namunali testda p95/p99 aynan "eng sekin 5% / 1%" foydalanuvchilarni ko'rsatadi.
Shuning uchun SLO'lar deyarli doim percentile bilan yoziladi: "GET /products uchun p95 < 500 ms", "o'rtacha < 300 ms" emas.
⚠️ Diqqat: Juda tez
500xatolar o'rtacha va p95 ni "chiroyli" qilib ko'rsatishi mumkin. Shuning uchun latency'ni har doim xato ulushi bilan birga baholang.
Throughput, concurrency va xatolar
| Metrika | Ma'nosi | DemoBozor SLO misoli |
|---|---|---|
Throughput (http_reqs, RPS) | Sekundiga bajarilgan so'rovlar | Aksiya soatida 300 RPS ko'tara olishi kerak |
Iteratsiya tezligi (iterations) | Sekundiga to'liq ssenariylar (masalan, "katalog → savatcha") | — |
Concurrency (vus) | Bir vaqtdagi virtual foydalanuvchilar | 500 VU |
Xato ulushi (http_req_failed) | Muvaffaqiyatsiz so'rovlar foizi | < 1% |
| Resurslar | CPU, xotira, DB ulanishlari, navbat uzunligi | CPU < 75%, DB pool < 80% |
k6'da http_req_failed — kutilgan javob kodlariga mos kelmagan so'rovlar ulushi (k6 hujjatiga ko'ra bu setResponseCallback bilan belgilanadi). Server tomonidagi resurslarni k6 o'lchamaydi — ular uchun monitoring kerak (Grafana, Prometheus, Datadog va h.k.; batafsil: DevOps: Observability).
Ochiq va yopiq yuklama modeli
- Yopiq model (closed) — VU'lar soni belgilanadi. Server sekinlashsa, har VU kamroq so'rov yuboradi → yuklama o'z-o'zidan kamayadi. Bu real hayotda ko'pincha muammoni yashiradi.
- Ochiq model (open) — sekundiga yangi kelayotgan iteratsiyalar soni belgilanadi (arrival rate). Server sekinlashsa ham yangi "foydalanuvchilar" kelaveradi — xuddi aksiya kunidagidek.
k6'da yopiq model — constant-vus, ramping-vus; ochiq model — constant-arrival-rate, ramping-arrival-rate executor'lari (7-bo'lim).
3. Little's Law va Apdex {#littles-law}
Little's Law: nechta VU kerak?
Navbat nazariyasidagi oddiy, lekin kuchli formula:
L = λ × W
L — tizimdagi bir vaqtdagi "mijozlar" soni (concurrency)
λ — kelish tezligi (sekundiga so'rov yoki iteratsiya)
W — bitta mijozning tizimda o'tkazgan o'rtacha vaqti (soniya)
Misol 1 (API darajasi). DemoBozor API'ga cho'qqida 50 so'rov/s keladi, o'rtacha javob 0.4 s. Demak bir vaqtda o'rtacha 50 × 0.4 = 20 ta so'rov "ichkarida" bo'ladi. Server 20 ta parallel so'rovni ko'tara olmasa — navbat paydo bo'ladi va latency o'sadi.
Misol 2 (VU sonini hisoblash). Analitikaga ko'ra aksiya soatida 18 000 ta "katalog → mahsulot → savatcha" ssenariysi bajariladi: λ = 18 000 / 3600 = 5 iteratsiya/s. Bitta iteratsiya (so'rovlar + foydalanuvchining o'ylash vaqti sleep) o'rtacha 12 s davom etadi. U holda kerakli VU soni: L = 5 × 12 = 60 VU.
💡 Maslahat:
sleep()(think time) qo'ymasangiz, 60 VU real 60 foydalanuvchidan ko'ra ancha ko'p so'rov yuboradi va natija real hayotga o'xshamaydi. Think time qiymatini analitikadan oling (sahifalar orasidagi o'rtacha vaqt).
Apdex: bitta raqamda "foydalanuvchi mamnunmi?"
Apdex (Application Performance Index) — 0 dan 1 gacha ball. Chegara T tanlanadi (masalan, 500 ms):
- mamnun (satisfied): javob ≤ T;
- chidaydigan (tolerating): T < javob ≤ 4T;
- norozi (frustrated): javob > 4T.
Apdex_T = (mamnunlar + chidaydiganlar / 2) / jami namunalar
Misol. T = 500 ms, 1000 so'rov: 850 tasi ≤ 0.5 s, 100 tasi 0.5–2 s oralig'ida, 50 tasi > 2 s. Apdex = (850 + 100/2) / 1000 = 0.90.
Apdex rahbariyatga tushuntirish uchun qulay, lekin muhandislik qarorlarini baribir percentile va xato ulushiga qarab qabul qiling.
4. Test turlari: smoke, load, stress, spike, soak, breakpoint {#test-turlari}
k6 yuklama profillari: smoke, average-load, stress, spike, soak va breakpoint testlari
k6 hujjatidagi "test turlari" jadvali asosida (moslashtirildi):
| Tur | VU / throughput | Davomiyligi | Qachon | DemoBozor misoli |
|---|---|---|---|---|
| Smoke | Past | Qisqa (soniya–daqiqa) | Skript yoki kod o'zgarganda | 2 VU × 30 s: skript va muhit ishlayaptimi? |
| Average-load | Odatiy prod darajasi | O'rta (5–60 daq) | Muntazam: odatiy kunda SLO bajariladimi? | Kunlik o'rtacha trafik × 30 daq |
| Stress | O'rtachadan yuqori | O'rta (5–60 daq) | Yuqori yuklama kutilganda | Aksiya prognozi × 1.5 |
| Spike | Juda yuqori, keskin | Qisqa (bir necha daq) | Mavsumiy aksiya, push, reklama | 20:00 push'dan keyingi sakrash |
| Soak | O'rtacha | Uzoq (soatlar) | Uzoq ishlashdagi muammolar | 4 soat: xotira oqishi, ulanishlar |
| Breakpoint | Sinmaguncha oshadi | Kerakcha | Sig'im chegarasini topish | Yangi serverlarga ko'chishdan oldin |
Qo'shimcha atamalar: capacity test (breakpoint'ga yaqin), scalability test (resurs qo'shilganda throughput qanchalik o'sadi), volume test (katta hajmdagi ma'lumot bilan, masalan 10 mln mahsulot).
⚠️ Diqqat: "Smoke" so'zi ikki ma'noda ishlatiladi. QA 4 dagi funksional smoke — "eng muhim funksiyalar ishlayaptimi?". Performance'dagi smoke — "skript va tizim minimal yuklamada to'g'ri ishlayaptimi?". Hisobotda qaysi biri ekanini aniq yozing.
k6 hujjati ikki muhim tavsiya beradi:
- Doim smoke'dan boshlang, keyin average-load, so'ng boshqa turlar.
- Oddiy shakllar ishlating: ramp-up → plato → ramp-down. Yuklamani ko'p marta ko'tarib-tushiradigan "rollercoaster" profillar natijani talqin qilishni qiyinlashtiradi.
🎯 Intervyuda: Soak test nimani topadi? — Qisqa testda ko'rinmaydigan, vaqt o'tishi bilan to'planadigan muammolarni: xotira oqishi (memory leak), yopilmagan DB ulanishlari, disk/log to'lib qolishi, sekin degradatsiya.
5. Jarayon: SLO'dan hisobotgacha {#jarayon}
1. Maqsad va SLO → "Nimani isbotlamoqchimiz?"
2. Yuklama modeli → qaysi ssenariylar, qancha, qanday nisbatda
3. Muhit va test data → prod'ga o'xshash, alohida, tayyorlangan
4. Monitoring → server metrikalari test bilan bir vaqtda
5. Bajarish → smoke → load → stress/spike/soak, takroriylik
6. Tahlil → thresholds, xatolar, percentile, bottleneck
7. Hisobot va qayta test → topilmalar, tavsiyalar, tuzatishdan keyin qayta o'lchash
1) SLO'ni o'lchanadigan qilib yozing
Yomon talab: "Sayt tez ishlashi kerak". Yaxshi talab:
| Endpoint / ssenariy | Yuklama | p95 | Xato ulushi |
|---|---|---|---|
GET /api/v1/products | 300 RPS | < 500 ms | < 1% |
POST /api/v1/orders | 20 RPS | < 1000 ms | < 0.5% |
| Login (OTP tekshirish) | 30 RPS | < 800 ms | < 1% |
2) Yuklama modeli (workload model)
Analitikadan oling: cho'qqi soatdagi trafik, ssenariylar nisbati, think time. DemoBozor misoli: 60% katalog va mahsulot sahifasi, 25% qidiruv, 10% savatcha, 5% buyurtma berish.
3) Muhit va ma'lumotlar
- Muhit prod'ga imkon qadar o'xshash bo'lsin: server o'lchamlari, baza hajmi, kesh sozlamalari.
- Har VU har xil foydalanuvchi va har xil mahsulotlar bilan ishlasin — aks holda hamma narsa keshdan qaytadi va natija "juda yaxshi" chiqadi.
- To'lov provayderi, SMS shlyuz kabi tashqi xizmatlarni stub/mock bilan almashtiring. Ularga yuklama berish — boshqa kompaniya tizimiga yuklama berish degani.
4) Monitoring
k6 faqat "mijoz tomondan" ko'radi. Sababni topish uchun test vaqtida server CPU/xotira, DB sekin so'rovlari, ulanishlar soni, navbatlar, GC pauzalarini ham kuzating.
Ko'p uchraydigan xatolar
| Xato | Oqibati |
|---|---|
| Yuklamani noutbukdan, Wi-Fi orqali berish | Server emas, sizning noutbuk/tarmoq "bo'g'iz" bo'lib qoladi |
sleep() yo'q | Real foydalanuvchiga o'xshamagan, haddan tashqari agressiv yuklama |
| Hamma VU bitta mahsulotni so'raydi | Kesh hammasini qaytaradi, baza sinovdan o'tmaydi |
| Faqat latency'ga qarash | Tez qaytgan 500 xatolar e'tibordan chetda qoladi |
| Server monitoringisiz test | "Sekin" ekanini bilasiz, lekin nega ekanini emas |
| Bir marta ishlatib xulosa qilish | Shovqin (noise) natijani buzadi — 2–3 marta takrorlang |
6. k6 bilan tanishuv: o'rnatish va birinchi skript {#k6-kirish}
Grafana k6 — ochiq kodli load testing vositasi. Skriptlar JavaScript (yoki TypeScript) da yoziladi, lekin k6 Node.js emas: u Go'da yozilgan va o'zining JS runtime'idan foydalanadi — shuning uchun ko'p npm paketlari ishlamaydi. Kuchli tomonlari: CLI-first, kodda yozilgan thresholds (CI uchun qulay), kam resurs bilan ko'p VU.
Versiyalar (2026-yil oktabr): v2.0.0 (2026-yil 11-may) eskirgan API va buyruqlarni olib tashladi, eng so'nggi reliz — v2.3.0 (2026-yil 21-sentabr). v2 dagi o'quvchiga ta'sir qiladigan o'zgarishlar:
| v1 da | v2 da |
|---|---|
k6 login cloud | k6 cloud login |
k6 cloud script.js | k6 cloud run script.js |
--no-summary | --summary-mode=disabled |
externally-controlled executor | olib tashlangan |
options.ext.loadimpact | options.cloud |
TypeScript fayllar k6 v0.57 dan beri qo'shimcha sozlamasiz ishga tushadi.
O'rnatish
# macOS (Homebrew)
brew install k6
# Windows
winget install k6 --source winget
# Docker
docker pull grafana/k6
# tekshirish
k6 version
Linux (Debian/Ubuntu, Fedora) uchun buyruqlarni rasmiy o'rnatish sahifasidan oling — u yerda repository kalitini qo'shish qadami bor.
Nishon: QuickPizza
QuickPizza — Grafana'ning o'quv ilovasi. Ikki variant:
# 1) Lokal (tavsiya etiladi — xohlagancha yuklama bera olasiz)
docker run --rm -it -p 3333:3333 ghcr.io/grafana/quickpizza-local:latest
# brauzerda: http://localhost:3333
# 2) Ommaviy demo: https://quickpizza.grafana.com
# faqat KICHIK testlar uchun (bir necha VU, qisqa vaqt)
Birinchi skript: smoke test
import http from "k6/http";
import { check, sleep } from "k6";
// BASE_URL berilmasa — lokal QuickPizza (Docker)
const BASE_URL = __ENV.BASE_URL || "http://localhost:3333";
export const options = {
vus: 2, // 2 ta virtual foydalanuvchi
duration: "20s", // 20 soniya davomida
};
export default function () {
const res = http.get(`${BASE_URL}/`);
check(res, {
"status 200": (r) => r.status === 200,
});
sleep(1); // "o'ylash vaqti" (think time)
}
k6 run smoke.js # lokal QuickPizza
k6 run -e BASE_URL=https://quickpizza.grafana.com smoke.js # ommaviy demo (kichik!)
k6 new my-test.js # tayyor shablon yaratish
k6 skriptining hayot sikli
| Qism | Necha marta ishlaydi | Nima uchun |
|---|---|---|
init (fayl tepasi: import, options, open()) | Har VU uchun bir marta | Sozlama, fayllarni o'qish |
setup() | Butun testda bir marta | Muhitni tekshirish, token olish; qaytgan qiymat default ga uzatiladi |
default (yoki exec funksiya) | Har VU qayta-qayta (iteratsiya) | Foydalanuvchi ssenariysi |
teardown() | Butun testda bir marta | Tozalash, xabar yuborish |
🧠 Esda tuting: VU — virtual foydalanuvchi (bitta "parallel ishchi"). Iteratsiya —
defaultfunksiyasining bir marta to'liq bajarilishi. 2 VU × 20 s, har iteratsiyadasleep(1)→ ko'pi bilan 2 × 20 = 40 iteratsiya; amalda biroz kamroq, chunki har iteratsiyaga so'rov vaqti ham qo'shiladi.
7. k6 chuqurroq: checks, thresholds, scenarios, metrikalar, data {#k6-chuqur}
Load test: stages + thresholds + tags + custom metrikalar
import http from "k6/http";
import { check, group, sleep } from "k6";
import { Trend, Rate } from "k6/metrics";
const BASE_URL = __ENV.BASE_URL || "http://localhost:3333";
// o'zimizning (custom) metrikalar
const pizzaCalories = new Trend("pizza_calories");
const vegetarianOk = new Rate("vegetarian_ok");
export const options = {
stages: [
{ duration: "30s", target: 10 }, // ramp-up: 0 → 10 VU
{ duration: "1m", target: 10 }, // plato: 10 VU
{ duration: "30s", target: 0 }, // ramp-down
],
thresholds: {
http_req_failed: ["rate<0.01"], // xatolar < 1%
http_req_duration: ["p(95)<500", "p(99)<1000"], // umumiy SLO
"http_req_duration{name:PizzaAPI}": ["p(95)<800"], // faqat pizza API uchun
checks: ["rate>0.99"],
vegetarian_ok: ["rate==1"],
},
};
export default function () {
group("bosh sahifa", () => {
const res = http.get(`${BASE_URL}/`, { tags: { name: "HomePage" } });
check(res, { "bosh sahifa 200": (r) => r.status === 200 });
});
group("pizza tavsiyasi", () => {
const payload = JSON.stringify({
maxCaloriesPerSlice: 500,
mustBeVegetarian: true,
excludedIngredients: [],
excludedTools: [],
maxNumberOfToppings: 6,
minNumberOfToppings: 2,
});
const res = http.post(`${BASE_URL}/api/pizza`, payload, {
headers: {
"Content-Type": "application/json",
Authorization: "token abcdef0123456789", // QuickPizza demo token
},
tags: { name: "PizzaAPI" },
});
const ok = check(res, {
"pizza 200": (r) => r.status === 200,
"pizza nomi bor": (r) => r.json("pizza.name") !== undefined,
});
if (ok) {
pizzaCalories.add(res.json("calories"));
vegetarianOk.add(res.json("vegetarian") === true);
}
});
sleep(1);
}
Muhim tushunchalar:
- **
check— tekshiruv, lekin o'zi testni yiqitmaydi**. Natijachecksmetrikasiga yoziladi. Testni yiqitish uchunchecks: ['rate>0.99']kabi threshold qo'ying. - **
thresholds— SLO'ning kodga aylangan ko'rinishi. Biror threshold buzilsa, k6 nol bo'lmagan exit code** bilan tugaydi → CI pipeline qizil bo'ladi. - **
tags: { name: 'PizzaAPI' }** — so'rovlarni guruhlash.'http_req_duration{name:PizzaAPI}'bilan faqat shu endpoint'ga alohida SLO qo'yasiz. - **
group()** — natijalarni mantiqiy bloklarga ajratadi (fullsummary rejimida guruh bo'yicha ko'rinadi). - **
res.json('pizza.name')** — JSON ichidan GJSON yo'li bilan qiymat olish. - Custom metrikalar:
Counter(yig'indi),Gauge(oxirgi qiymat),Rate(ulush),Trend(taqsimot: avg, p95...).
💡 Maslahat: Threshold buzilganda testni darhol to'xtatish uchun:
http_req_failed: [{ threshold: 'rate<0.05', abortOnFail: true, delayAbortEval: '30s' }].delayAbortEval— boshida yetarli namuna yig'ilishini kutish.
Scenarios va executor'lar
Bitta testda bir nechta ssenariyni turli yuklama shakllari bilan aralashtirish mumkin. k6 v2 dagi executor'lar:
| Executor | Model | Nima qiladi |
|---|---|---|
shared-iterations | yopiq | Belgilangan jami iteratsiyalarni VU'lar bo'lishib bajaradi |
per-vu-iterations | yopiq | Har VU aniq N marta bajaradi |
constant-vus | yopiq | Doimiy VU soni, belgilangan vaqt |
ramping-vus | yopiq | VU soni bosqichma-bosqich o'zgaradi (stages) |
constant-arrival-rate | ochiq | Sekundiga doimiy iteratsiya boshlanadi |
ramping-arrival-rate | ochiq | Iteratsiya tezligi bosqichma-bosqich o'zgaradi |
import http from "k6/http";
import { check, sleep } from "k6";
const BASE_URL = __ENV.BASE_URL || "http://localhost:3333";
const HEADERS = {
"Content-Type": "application/json",
Authorization: "token abcdef0123456789",
};
export const options = {
scenarios: {
// ochiq model: sekundiga 10 ta yangi "tashrif", javob sekinlashsa ham
browse: {
executor: "constant-arrival-rate",
exec: "browse",
rate: 10,
timeUnit: "1s",
duration: "2m",
preAllocatedVUs: 20,
maxVUs: 50,
},
// yopiq model: 5 VU, 30 soniyadan keyin boshlanadi
order: {
executor: "ramping-vus",
exec: "order",
startTime: "30s",
stages: [
{ duration: "30s", target: 5 },
{ duration: "1m", target: 5 },
],
},
},
thresholds: {
"http_req_duration{scenario:browse}": ["p(95)<400"],
"http_req_duration{scenario:order}": ["p(95)<900"],
http_req_failed: ["rate<0.01"],
},
};
export function browse() {
const res = http.get(`${BASE_URL}/`);
check(res, { "browse 200": (r) => r.status === 200 });
}
export function order() {
const res = http.post(
`${BASE_URL}/api/pizza`,
JSON.stringify({
mustBeVegetarian: true,
maxNumberOfToppings: 5,
minNumberOfToppings: 2,
}),
{ headers: HEADERS },
);
check(res, { "order 200": (r) => r.status === 200 });
sleep(2);
}
Scenario parametrlari: executor (majburiy), exec (qaysi funksiya), startTime, gracefulStop, env, tags, options (masalan, brauzer sozlamalari).
Spike test: aksiya push'i
import http from "k6/http";
import { check } from "k6";
const BASE_URL = __ENV.BASE_URL || "http://localhost:3333";
export const options = {
scenarios: {
aksiya_spike: {
executor: "ramping-arrival-rate",
startRate: 5, // soniyasiga 5 iteratsiya
timeUnit: "1s",
preAllocatedVUs: 50,
maxVUs: 300,
stages: [
{ target: 5, duration: "1m" }, // odatiy fon trafik
{ target: 100, duration: "10s" }, // push yuborildi — keskin sakrash
{ target: 100, duration: "1m" }, // cho'qqi
{ target: 5, duration: "10s" }, // pasayish
{ target: 5, duration: "2m" }, // tizim tiklandimi?
],
},
},
thresholds: {
http_req_failed: [
{ threshold: "rate<0.05", abortOnFail: true, delayAbortEval: "30s" },
],
http_req_duration: ["p(95)<1500"],
},
};
export default function () {
const res = http.get(`${BASE_URL}/`);
check(res, { "status 200": (r) => r.status === 200 });
}
⚠️ Diqqat: Bu skript soniyasiga 100 iteratsiyagacha yuklama beradi — uni faqat lokal QuickPizza yoki o'z test muhitingizga qarshi ishlating. Ommaviy demo saytlar kichik testlar uchun mo'ljallangan.
Oxiridagi 2 daqiqalik "tinch" bosqich muhim: spike'dan keyin tizim o'zi tiklanadimi (latency normal holatga qaytadimi, xatolar to'xtaydimi) — buni ham tekshiramiz.
Soak va breakpoint profillari
// Soak: 4 soat o'rtacha yuklama
export const soakOptions = {
stages: [
{ duration: "5m", target: 50 },
{ duration: "4h", target: 50 },
{ duration: "5m", target: 0 },
],
};
// Breakpoint: sinmaguncha oshiramiz, xatolar 5% dan oshsa — to'xtatamiz
export const breakpointOptions = {
scenarios: {
breakpoint: {
executor: "ramping-arrival-rate",
preAllocatedVUs: 100,
maxVUs: 2000,
stages: [{ duration: "30m", target: 2000 }],
},
},
thresholds: {
http_req_failed: [{ threshold: "rate<0.05", abortOnFail: true }],
http_req_duration: [{ threshold: "p(95)<2000", abortOnFail: true }],
},
};
(Real skriptda bularning birini export const options = ... sifatida ishlatasiz.)
Test data: SharedArray va setup()
import http from "k6/http";
import { check, sleep } from "k6";
import { SharedArray } from "k6/data";
import exec from "k6/execution";
const BASE_URL = __ENV.BASE_URL || "http://localhost:3333";
// open() faqat init qismida ishlaydi; SharedArray xotirani VU'lar orasida bo'lishadi
const tokens = new SharedArray("tokens", function () {
return JSON.parse(open("./data/tokens.json")).tokens;
});
export const options = { vus: 5, duration: "30s" };
export function setup() {
const res = http.get(BASE_URL);
if (res.status !== 200) {
throw new Error(`Muhit tayyor emas: status ${res.status}`);
}
return { startedAt: new Date().toISOString() }; // default() ga uzatiladi
}
export default function (data) {
// har bir VU test oxirigacha bitta "foydalanuvchi" bo'lib qoladi
const token = tokens[(exec.vu.idInTest - 1) % tokens.length];
const res = http.post(
`${BASE_URL}/api/pizza`,
JSON.stringify({ mustBeVegetarian: true }),
{
headers: {
"Content-Type": "application/json",
Authorization: `token ${token}`,
},
},
);
check(res, { "pizza 200": (r) => r.status === 200 });
sleep(1);
}
export function teardown(data) {
console.log(`Test ${data.startedAt} da boshlangan edi`);
}
data/tokens.json:
{
"tokens": ["loadtestuser0004", "loadtestuser0005", "loadtestuser0006"]
}
🧠 Esda tuting:
open()faqat init qismida ishlaydi (defaultichida emas). Katta fayllarniSharedArraybilan o'qing — aks holda har VU faylning o'z nusxasini xotirada saqlaydi.
k6 browser: frontend metrikalari bilan
k6 da k6/browser moduli bor — haqiqiy Chromium brauzerida sahifani ochib, Web Vitals (LCP, CLS, INP, FCP, TTFB) ni o'lchaydi. Kompyuterda Chromium asosidagi brauzer (masalan, Google Chrome) bo'lishi kerak.
import { browser } from "k6/browser";
import { check } from "k6";
const BASE_URL = __ENV.BASE_URL || "http://localhost:3333";
export const options = {
scenarios: {
ui: {
executor: "shared-iterations",
vus: 1,
iterations: 3,
options: { browser: { type: "chromium" } },
},
},
thresholds: {
browser_web_vital_lcp: ["p(75)<2500"],
browser_web_vital_cls: ["p(75)<0.1"],
},
};
export default async function () {
const page = await browser.newPage();
try {
await page.goto(BASE_URL);
await page.locator('button[name="pizza-please"]').click();
const title = await page.locator("h1").textContent();
check(title, { "sarlavha bor": (t) => t !== null && t.length > 0 });
} finally {
await page.close();
}
}
Odatiy amaliyot: ko'p protokol (HTTP) VU + bir nechta brauzer VU — backend yuklama ostida bo'lganda foydalanuvchi sahifani qanday his qilishini ko'rish. k6 da Playwright uslubidagi expect assertion'lari ham bor (k6-testing kutubxonasi), lekin u hozircha preview holatida.
8. Natijani o'qish, hisobot va CI {#natija}
End-of-test summary
k6 v2 da summary standart holatda compact rejimda chiqadi (--summary-mode=full — guruh va ssenariylar bo'yicha batafsil). Quyida rasmiy k6 hujjatidagi compact namunadan qisqartirilgan parcha:
█ THRESHOLDS
http_req_duration
✓ 'p(95)<1500' p(95)=148.21ms
✓ 'p(90)<2000' p(90)=146.88ms
http_req_failed
✓ 'rate<0.01' rate=0.00%
█ TOTAL RESULTS
checks_total.......................: 90 13.122179/s
checks_succeeded...................: 100.00% 90 out of 90
checks_failed......................: 0.00% 0 out of 90
HTTP
http_req_duration..................: avg=140.36ms min=119.08ms med=140.96ms max=154.63ms p(90)=146.88ms p(95)=148.21ms
{ expected_response:true }.......: avg=140.36ms min=119.08ms med=140.96ms max=154.63ms p(90)=146.88ms p(95)=148.21ms
http_req_failed....................: 0.00% 0 out of 45
http_reqs..........................: 45 6.56109/s
EXECUTION
iteration_duration.................: avg=152.38ms min=119.37ms med=141.27ms max=684.62ms p(90)=147.11ms p(95)=148.39ms
iterations.........................: 45 6.56109/s
vus................................: 1 min=1 max=1
Qanday o'qiladi:
- THRESHOLDS — eng birinchi qaraladigan joy.
✓— SLO bajarildi,✗— buzildi. - checks — funksional to'g'rilik: yuklama ostida javoblar hali ham to'g'rimi?
- http_req_duration —
med(p50) vap(95)ni solishtiring. Ular orasidagi katta farq — "dum" (tail latency) muammosi. - **
{ expected_response:true }** qatori — faqat muvaffaqiyatli javoblar vaqti. Asosiy qator bilan farq qilsa, xatoli javoblar vaqtni buzayotgan bo'ladi. - http_req_failed va http_reqs — xato ulushi va throughput (sekundiga so'rov).
- vus — haqiqatda nechta VU ishlagan (arrival-rate'da
maxVUsyetmasa, k6 ogohlantiradi).
Bottleneck'ni qidirish
| Belgi | Ehtimoliy sabab | Nimani tekshirish |
|---|---|---|
| Yuklama oshgani sari p95 keskin o'sadi, RPS o'smaydi | Sig'im tugadi ("tizza" nuqtasi) | CPU, DB ulanishlari, thread pool |
Ma'lum vaqtdan keyin 503/timeout'lar | Connection pool yoki navbat to'ldi | Pool o'lchami, navbat uzunligi |
| Soak testda latency asta-sekin o'sadi | Xotira oqishi, yopilmagan resurslar | Xotira grafigi, GC, ulanishlar soni |
| Faqat bitta endpoint sekin | Sekin SQL, N+1 so'rov, indeks yo'q | DB slow query log, EXPLAIN (QA 12) |
http_req_waiting kichik, receiving katta | Javob juda og'ir | Payload hajmi, siqish (gzip/br), pagination |
| Lokal tez, CI'da sekin | Load generator'ning o'zi bo'g'iz | Generator CPU/tarmog'i |
Natijalarni saqlash va vizualizatsiya
k6 run --out json=results.json load.js # har bir nuqta JSON faylga
K6_WEB_DASHBOARD=true k6 run load.js # jonli dashboard: http://127.0.0.1:5665
K6_WEB_DASHBOARD=true K6_WEB_DASHBOARD_EXPORT=report.html k6 run load.js # HTML hisobot
Real vaqtda metrikalarni Grafana Cloud k6, Prometheus remote write, InfluxDB, OpenTelemetry va boshqa tizimlarga ham uzatish mumkin.
Hisobot shabloni
# Performance test hisoboti — DemoBozor aksiya tayyorgarligi
Maqsad: Aksiya kuni 300 RPS da katalog SLO'si bajariladimi?
Muhit: staging-perf (prod bilan bir xil instance turi), DB: 2 mln mahsulot
Versiya: api v2.14.0, build 1842
Yuklama: ramping-arrival-rate 0→300 it/s 10 daq, 300 it/s da 30 daq
Natijalar:
| Metrika | SLO | Natija | Holat |
| GET /products p95 | < 500 ms | 430 ms | OK |
| POST /orders p95 | < 1000 ms | 1840 ms | FAIL |
| Xato ulushi | < 1% | 0.4% | OK |
Topilmalar: POST /orders da DB lock kutish; 250+ it/s da pool 100% band
Tavsiyalar: orders jadvaliga indeks, pool 20→40, qayta test
Ilovalar: report.html, Grafana dashboard havolasi, skript commit'i
💡 Maslahat: Hisobotda faqat "yiqildi/o'tdi" emas, qaysi yuklamada buzilish boshlanganini yozing ("230 it/s gacha SLO bajarildi, 250 dan keyin p95 2 baravar o'sdi"). Bu jamoaga sig'imni rejalashtirishga yordam beradi.
CI'da performance smoke
Har PR'da og'ir load test kerak emas, lekin qisqa smoke perf test regressiyani erta ushlaydi. GitHub Actions uchun Grafana'ning rasmiy action'lari bor:
name: perf-smoke
on:
pull_request:
jobs:
k6:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: grafana/setup-k6-action@v1
- uses: grafana/run-k6-action@v1
with:
path: ./perf/smoke.js
flags: -e BASE_URL=${{ vars.STAGING_URL }}
Threshold buzilsa, k6 nol bo'lmagan kod bilan chiqadi va job qizil bo'ladi — bu quality gate vazifasini bajaradi. Og'ir testlarni (stress, soak) esa kechasi (schedule) yoki reliz oldidan alohida ishlating. CI haqida batafsil: QA 21.
9. Boshqa vositalar: JMeter, Gatling, Locust {#boshqa-vositalar}
| Vosita | Skript tili | Kuchli tomoni | E'tibor bering |
|---|---|---|---|
| k6 | JavaScript / TypeScript | CLI-first, thresholds-as-code, kam resurs | Node.js emas — npm paketlari cheklangan |
| Apache JMeter | GUI'da test plan (.jmx, XML) | Ko'p protokol, katta plagin ekotizimi | Yuklamani GUI'dan emas, CLI (non-GUI) rejimda bering |
| Gatling | Java, Scala, Kotlin, JavaScript/TypeScript | Kuchli DSL, chiroyli HTML hisobot | JVM asosida ishlaydi |
| Locust | Python | Python bilan oson, web UI | Python bilmaydigan jamoaga mos emas |
JMeter'da yuklama testi va HTML hisobotni CLI'dan ishga tushirish (rasmiy hujjatdagi format):
jmeter -n -t test-plan.jmx -l results.jtl -e -o report/
Locust'dagi eng oddiy fayl (locustfile.py, rasmiy quickstart'dagi misolga o'xshash):
from locust import HttpUser, task
class KatalogUser(HttpUser):
@task
def katalog(self):
self.client.get("/")
locust buyrug'idan keyin web UI http://localhost:8089 da ochiladi.
💡 Maslahat: Vositani jamoa tiliga qarab tanlang: frontend/JS jamoa — k6, Java jamoa — Gatling yoki JMeter, Python jamoa — Locust. Tushunchalar (SLO, percentile, ochiq/yopiq model) hammasida bir xil.
10. Frontend va mobil performance {#frontend-mobil}
Backend 200 ms da javob bersa ham, foydalanuvchi sahifani 5 soniyada ko'rishi mumkin: og'ir rasmlar, bloklovchi JavaScript, kech yuklanadigan shriftlar.
Core Web Vitals (web.dev)
| Metrika | Nimani o'lchaydi | "Yaxshi" chegara |
|---|---|---|
| LCP (Largest Contentful Paint) | Asosiy kontent ko'rinish tezligi | ≤ 2.5 s |
| INP (Interaction to Next Paint) | Bosish/yozishga javob tezligi | ≤ 200 ms |
| CLS (Cumulative Layout Shift) | Sahifa elementlarining "sakrashi" | ≤ 0.1 |
Chegaralar sahifa yuklanishlarining 75-percentile'ida, mobil va desktop uchun alohida baholanadi. INP 2024-yilda FID o'rniga Core Web Vital bo'ldi.
QA uchun amaliy tekshiruvlar (DemoBozor mahsulot sahifasi):
- Chrome DevTools → Lighthouse — lab o'lchovi; Performance paneli — nima sekin ekanini ko'rish (QA 9);
- Network throttling (masalan, "Slow 4G") bilan sahifani ochib ko'ring;
- narx yoki banner kech yuklanib, tugmalarni pastga "itarib yuborsa" — bu CLS bug'i;
- rasm o'lchamlari, lazy loading, keshlash header'lari.
🧠 Esda tuting: Lab data (Lighthouse) — bitta qurilmada, boshqariladigan sharoitda. Field data (real foydalanuvchilar, RUM) — haqiqiy qurilma va tarmoqlar. Ikkalasi ham kerak.
Mobil ilovalar
| Nima | Qanday tekshiriladi |
|---|---|
| Cold/warm start vaqti | Ilovani to'liq yopib ochish; Xcode Instruments, Android Studio Profiler |
| Xotira va oqishlar | Instruments (Allocations, Leaks), Android Profiler; uzoq ishlatish ssenariysi |
| Kadrlar tushishi (jank) | Uzun ro'yxatlarni scroll qilish, animatsiyalar |
| Batareya va tarmoq | Fon rejimidagi so'rovlar, keraksiz polling |
| Sekin tarmoq | iOS Network Link Conditioner, Proxyman Network Conditions |
Mobil testlash bo'yicha to'liq checklist — QA 14.
11. Etika va xavfsizlik qoidalari {#etika}
Load test — bu ataylab katta trafik yaratish. Noto'g'ri nishonga qaratilsa, u DoS hujumidan farq qilmaydi.
- Faqat o'zingizga tegishli yoki yozma ruxsat olingan tizimlarni testlang. Boshqa kompaniya saytini "qiziqish uchun" yuklama bilan tekshirish — qonunbuzarlik bo'lishi mumkin.
- Umumiy (shared) muhitda test qilishdan oldin DevOps va navbatchi jamoani ogohlantiring, vaqtni kelishing.
- Tashqi xizmatlarni (to'lov, SMS, xaritalar) stub qiling — ularning limitlari va narxlari bor.
- Har doim to'xtatish mezoni bo'lsin:
abortOnFail, maksimal VU, maksimal davomiylik. - Prod'da test faqat alohida kelishuv, monitoring va reja bilan (masalan, past trafikli soatda).
- Real foydalanuvchi ma'lumotlarini emas, test data'dan foydalaning.
- Ommaviy demo nishonlar (masalan, quickpizza.grafana.com) — faqat kichik o'quv testlari uchun; katta yuklama uchun lokal nusxani ishga tushiring.
12. Amaliy mashqlar {#mashqlar}
Mashq 1: O'rtacha vs mediana
Qidiruv endpoint'ining 10 ta javob vaqti (ms): 200, 210, 190, 205, 2400, 198, 202, 215, 207, 193. O'rtacha va medianani hisoblang. Qaysi biri foydalanuvchi tajribasini yaxshiroq ifodalaydi va SLO'ni qanday yozgan bo'lardingiz?
<details> <summary>💡 Javobni ko'rish</summary>
- Yig'indi: 200+210+190+205+2400+198+202+215+207+193 = 4220 → o'rtacha 422 ms.
- Saralangan: 190, 193, 198, 200, 202, 205, 207, 210, 215, 2400 → mediana = (202 + 205) / 2 = 203.5 ms.
Mediana "odatiy" foydalanuvchini ko'rsatadi; o'rtacha bitta 2.4 s lik so'rov tufayli ikki baravar oshib ketgan. SLO percentile bilan yoziladi: masalan, "GET /search uchun p95 < 500 ms va xato ulushi < 1%" — shunda sekin "dum" ham nazoratda bo'ladi.
</details>
Mashq 2: Qaysi test turi?
Har bir vaziyat uchun test turini tanlang:
- Yangi k6 skript yozildi, uni birinchi marta ishga tushiryapsiz.
- Server 6 soat ishlagandan keyin sekinlashib qolayotganidan shikoyat bor.
- "Hayit aksiyasi" push xabari 2 mln foydalanuvchiga bir vaqtda yuboriladi.
- Yangi DB serverga ko'chishdan oldin "maksimum nechta buyurtma/s ko'taramiz?" degan savol.
- Har haftalik reliz: oddiy kunlik trafikda SLO buzilmadimi?
<details> <summary>💡 Javobni ko'rish</summary>
- Smoke — skript va muhit ishlashini minimal yuklamada tekshirish.
- Soak — uzoq vaqtli o'rtacha yuklama: xotira oqishi, yopilmagan ulanishlar.
- Spike — qisqa vaqtda keskin sakrash va undan keyingi tiklanish.
- Breakpoint (capacity) — sinmaguncha oshirib, chegarani topish.
- Average-load — odatiy yuklamada regressiya bormi.
</details>
Mashq 3: Little's Law bilan VU hisoblash
Prognoz: aksiya soatida daqiqasiga 120 ta buyurtma ssenariysi. Bitta ssenariy: so'rovlar jami ~2 s + foydalanuvchining o'ylash vaqti 28 s. Nechta VU kerak? Agar sleep() ni olib tashlasangiz, shu throughput uchun nechta VU yetadi va bu nimani anglatadi?
<details> <summary>💡 Javobni ko'rish</summary>
- λ = 120 / 60 = 2 iteratsiya/s; W = 2 + 28 = 30 s → L = 2 × 30 = 60 VU.
sleep()siz: W ≈ 2 s → L = 2 × 2 = 4 VU xuddi shu 2 it/s ni beradi.
Xulosa: think time'siz test real concurrency'ni (bir vaqtdagi sessiyalar, ochiq ulanishlar, xotiradagi sessiyalar) ancha kam ko'rsatadi. Real hayotga yaqin model uchun think time'ni analitikadan oling.
</details>
Mashq 4: Thresholds yozing
SLO: (a) barcha so'rovlarda xato < 0.5%; (b) name:Checkout tegli so'rovlar uchun p95 < 800 ms va p99 < 1500 ms; (c) check'larning 99% dan ko'prog'i o'tsin; (d) xato ulushi 10% dan oshsa, 20 soniyalik "isinish"dan keyin test darhol to'xtasin. options.thresholds ni yozing.
<details> <summary>💡 Javobni ko'rish</summary>
export const options = {
thresholds: {
http_req_failed: [
"rate<0.005",
{ threshold: "rate<0.10", abortOnFail: true, delayAbortEval: "20s" },
],
"http_req_duration{name:Checkout}": ["p(95)<800", "p(99)<1500"],
checks: ["rate>0.99"],
},
};
Bitta metrikaga bir nechta threshold berish mumkin: oddiy satr ko'rinishi ham, abortOnFail li obyekt ham bir massivda turishi mumkin. So'rovlarga tags: { name: 'Checkout' } qo'yishni unutmang.
</details>
Mashq 5: Summary'ni talqin qiling
Quyidagi — o'quv misoli (raqamlar xayoliy). Nima bo'lgan va keyingi qadamingiz qanday?
█ THRESHOLDS
http_req_duration
✗ 'p(95)<500' p(95)=912.40ms
http_req_failed
✗ 'rate<0.01' rate=3.20%
█ TOTAL RESULTS
HTTP
http_req_duration..................: avg=310.11ms min=95.20ms med=180.33ms max=30.01s p(90)=640.12ms p(95)=912.40ms
{ expected_response:true }.......: avg=205.47ms min=95.20ms med=176.90ms max=1.20s p(90)=420.55ms p(95)=488.02ms
http_req_failed....................: 3.20% 154 out of 4800
http_reqs..........................: 4800 39.6/s
<details> <summary>💡 Javobni ko'rish</summary>
- Ikkala threshold buzilgan → test FAIL, CI qizil.
- Muvaffaqiyatli javoblar (
expected_response:true) p95 = 488 ms — ya'ni SLO'ga deyarli mos. Umumiy p95 ni xatoli javoblar buzmoqda. max=30.01s— timeout'ga o'xshaydi: 3.2% (154 ta) so'rov uzoq kutib, xato bilan tugagan.- Keyingi qadamlar: xatolar qaysi endpoint va qaysi status kodida ekanini aniqlash (tag'lar,
--out json), server loglari va monitoringda shu vaqtdagi CPU/DB pool/timeout'larni ko'rish, kichikroq yuklamada qayta ishga tushirib, buzilish qaysi nuqtada boshlanishini topish.
</details>
Mashq 6: Spike ssenariysini yozing
Talab: 2 daqiqa davomida soniyasiga 10 iteratsiya (fon), keyin 15 soniyada 150 it/s gacha sakrash, 1 daqiqa ushlab turish, 15 soniyada 10 ga qaytish va yana 3 daqiqa kuzatish. Executor va stages ni yozing.
<details> <summary>💡 Javobni ko'rish</summary>
export const options = {
scenarios: {
spike: {
executor: "ramping-arrival-rate",
startRate: 10,
timeUnit: "1s",
preAllocatedVUs: 100,
maxVUs: 500,
stages: [
{ target: 10, duration: "2m" },
{ target: 150, duration: "15s" },
{ target: 150, duration: "1m" },
{ target: 10, duration: "15s" },
{ target: 10, duration: "3m" },
],
},
},
};
Ochiq model (ramping-arrival-rate) tanlandi: server sekinlashsa ham yangi foydalanuvchilar kelishda davom etadi — haqiqiy push'dagi kabi. maxVUs yetmasa, k6 ogohlantirish beradi — demak generator'ga ko'proq VU kerak.
</details>
Mashq 7: Performance bug report
Stress testda POST /api/v1/orders 250 it/s dan keyin p95 3.1 s ga chiqdi va 4% 503 qaytdi. Bug report'da qaysi ma'lumotlar bo'lishi kerak? (QA 8 formatini eslang.)
<details> <summary>💡 Javobni ko'rish</summary>
- Sarlavha: "
POST /api/v1/orders: 250 it/s dan yuqori yuklamada p95 3.1 s va 4% 503 (SLO: p95 < 1 s, xato < 0.5%)". - Muhit: staging-perf, API versiyasi/build, DB hajmi, instance turlari.
- Qayta hosil qilish: skript fayli (commit havolasi), aniq
options(executor, stages), ishga tushirish buyrug'i. - Kutilgan/haqiqiy natija: SLO jadvali bilan solishtirish.
- Dalillar: k6 summary, HTML hisobot, Grafana dashboard skrinshotlari (CPU, DB pool, xatolar) — vaqt oralig'i bilan.
- Kuzatuv: buzilish qaysi yuklamadan boshlangani, 503 lar qaysi komponentdan kelgani (gateway yoki servis).
- Jiddiylik/ustuvorlik: aksiya sanasiga bog'liq holda (aksiyagacha muddat qisqa bo'lsa — yuqori).
</details>
13. O'zingizni tekshiring {#checklist}
- [ ] Nega SLO o'rtacha emas, percentile bilan yozilishini tushuntira olaman
- [ ] Little's Law bilan kerakli VU sonini hisoblay olaman
- [ ] 6 ta test turini va ularning maqsadini ayta olaman
- [ ] Ochiq va yopiq yuklama modelining farqini bilaman
- [ ] k6'da
stages,thresholds,scenarios,tagsva custom metrika yoza olaman - [ ] Summary'ni o'qib, keyingi qadamni belgilay olaman
- [ ] Core Web Vitals chegaralarini bilaman
- [ ] Load test etikasi qoidalariga amal qilaman
Xulosa {#xulosa}
- Performance testing — tezlik, barqarorlik va sig'imni o'lchash; funksional testlar topmaydigan muammolarni topadi.
- SLO'larni percentile (p95/p99) va xato ulushi bilan yozing; o'rtacha qiymat aldaydi.
- Little's Law (
L = λ × W) VU sonini hisoblashga, Apdex natijani biznes tiliga o'girishga yordam beradi. - Har doim smokedan boshlang; keyin average-load, stress, spike, soak, breakpoint — maqsadga qarab.
- k6 v2:
thresholdsSLO'ni kodga aylantiradi va CI'da quality gate bo'ladi; ochiq model uchun arrival-rate executor'larini ishlating. - k6 faqat mijoz tomonini ko'radi — sababni topish uchun server monitoringi shart.
- Foydalanuvchi tezligi faqat backend emas: Core Web Vitals (LCP ≤ 2.5 s, INP ≤ 200 ms, CLS ≤ 0.1) va mobil start/xotira ham muhim.
- Keyingi dars: QA 24: Security testing asoslari — OWASP Top 10:2025, IDOR, injection va QA xavfsizlik checklisti
Manbalar {#manbalar}
- Grafana k6 — rasmiy hujjatlar
- grafana/k6 — GitHub releases
- k6 v2.0.0 reliz eslatmalari (breaking changes)
- k6 — Install k6
- k6 — Load test types
- k6 — Thresholds
- k6 — Executors
- k6 — Built-in metrics
- k6 — End of test summary
- k6 — Web dashboard
- k6 — Using k6 browser
- grafana/quickpizza — GitHub
- grafana/run-k6-action — GitHub
- web.dev — Web Vitals
- Wikipedia — Apdex
- Wikipedia — Little's law
- Apache JMeter — Generating Report Dashboard
- Gatling — JavaScript/TypeScript installation guide
- Locust — Quickstart