Load testing k6-ով
Պարզեք, թե ինչպես է ձեր համակարգը վարվում տրաֆիկի տակ, նախքան ձեր օգտատերերը կպարզեն։
30 վայրկյանում
Load testing-ը ձեր համակարգին ուղարկում է իրատեսական տրաֆիկ՝ արագությունը չափելու և սահմանները գտնելու համար։ k6-ը Grafana Labs-ի բաց կոդով load testing գործիք է․ թեստերը գրում եք JavaScript-ով կամ TypeScript-ով, աշխատեցնում command line-ից և սահմանում pass/fail threshold-ներ, օրինակ՝ «հարցումների 95%-ը 400 ms-ից պակաս»։ Ընթացիկ հիմնական գիծը k6 2.x-ն է, և այն բնականորեն տեղավորվում է CI pipeline-ներում։
Իմ ամենօրյա stack-ում չէ․ գիտեմ հիմնական գաղափարները և մանրամասները կսովորեմ, երբ նախագիծը դա պահանջի։
Ինչու է սա կարևոր
- Ֆունկցիոնալ թեստերը ապացուցում են, որ կոդն աշխատում է մեկ օգտատիրոջ համար։ Load test-երը ապացուցում են, որ այն դեռ աշխատում է միաժամանակ հազարի համար, և հենց այստեղ են երևում connection pool-երը, lock-երը և դանդաղ query-ները։
- Դրանք capacity planning-ը վերածում են թվերի․ քանի հարցում վայրկյանում է մշակում մեկ սերվերը և որտեղ է հաջորդ bottleneck-ը։
- Թիմերը դրանք աշխատեցնում են launch-երից, կամպանիաներից և մեծ refactor-ներից առաջ, որպեսզի ակցիան կամ մարքեթինգային email-ը չվերածվի outage-ի։
- Դրանք լրացնում են unit և integration թեստերին (PHPUnit, Jest)․ վերջիններս բռնում են սխալ վարքը, իսկ load test-երը՝ դանդաղ և փխրուն վարքը։
Ինչպես է աշխատում
01Performance թեստերի տեսակները
«Load test» արտահայտությունն օգտագործվում է ազատ, բայց յուրաքանչյուր տեսակ պատասխանում է տարբեր հարցի։ Smoke test-ը աշխատեցնում է փոքրիկ բեռ՝ ստուգելու, որ script-ը և համակարգն աշխատում են։ Average-load test-ը մոդելավորում է սովորական տրաֆիկ՝ հաստատելու, որ թիրախներին համապատասխանում եք։ Stress test-ը բեռը տանում է սովորականից այն կողմ՝ տեսնելու, թե ինչպես է համակարգը վատթարանում։ Spike test-ը կտրուկ թռիչք է անում, ինչպես push notification-ից հետո։ Soak (endurance) test-ը սովորական բեռը պահում է ժամերով՝ memory leak-եր և ռեսուրսների դանդաղ սպառում գտնելու համար։ Breakpoint test-ը բեռը մեծացնում է, մինչև ինչ-որ բան կոտրվի, որպեսզի գտնի իրական capacity-ն։ Սկսեք smoke-ից և average load-ից․ մյուսներն ավելացրեք, երբ իմանաք ձեր baseline-ը։
- Throughput՝ վայրկյանում համակարգի ավարտած հարցումների կամ iteration-ների քանակը։
- Latency percentile-ներ՝ p95-ը նշանակում է, որ հարցումների 95%-ն ավելի արագ էր, քան այս արժեքը։
- Error rate՝ ձախողված հարցումների բաժինը, որը հաճախ առաջինն է կոտրվում։
02Ձեր առաջին k6 script-ը
k6 script-ը ES module է։ options export-ը նկարագրում է բեռը և pass/fail կանոնները․ default ֆունկցիան այն է, ինչ յուրաքանչյուր virtual user (VU) աշխատեցնում է ցիկլով։ VU-ն մոդելավորված օգտատեր է, որը ձեր ֆունկցիան աշխատեցնում է մյուսների հետ զուգահեռ։ check()-ը ստուգում է պատասխանները՝ առանց թեստը կանգնեցնելու․ threshold-ները մետրիկաները վերածում են pass կամ fail արդյունքի, և երբ threshold-ը ձախողվում է, k6-ը դուրս է գալիս ոչ զրոյական կոդով, ինչը և կոտրում է CI build-ը։ sleep()-ը ավելացնում է think time, որպեսզի VU-ն վարվի իրական մարդու պես, ոչ թե խիտ ցիկլի։ k6-ը TypeScript ֆայլերն աշխատեցնում է ուղղակիորեն, ուստի մեծ suite-երում կարող եք տիպեր օգտագործել։
import http from "k6/http";
import { check, sleep } from "k6";
export const options = {
vus: 20,
duration: "2m",
thresholds: {
http_req_failed: ["rate<0.01"], // under 1% errors
http_req_duration: ["p(95)<400", "p(99)<1000"], // ms
},
};
export default function () {
const res = http.get("https://staging.example.com/api/products?page=1");
check(res, { "status is 200": (r) => r.status === 200 });
sleep(1);
}
03Scenario-ներ և executor-ներ՝ open ընդդեմ closed մոդելների
Scenario-ները թույլ են տալիս ճշգրիտ ձևավորել բեռը և միաժամանակ աշխատեցնել մի քանի pattern։ Executor-ներն են որոշում՝ ինչպես։ Closed-model executor-ները (constant-vus, ramping-vus) զբաղված են պահում որոշակի քանակով VU-ներ․ եթե համակարգը դանդաղում է, յուրաքանչյուր VU ավելի քիչ հարցում է անում, ինչը թաքցնում է խնդիրը։ Open-model executor-ները (constant-arrival-rate, ramping-arrival-rate) նոր iteration-ներ են սկսում ֆիքսված տեմպով՝ անկախ պատասխանի ժամանակից, ինչը համապատասխանում է իրական ինտերնետային տրաֆիկին․ օգտատերերը շարունակում են գալ, նույնիսկ երբ ձեր կայքը դանդաղ է։ API-ի capacity թեստերի համար նախընտրեք arrival-rate executor-ներ և տվեք նրանց բավարար preAllocatedVUs և maxVUs՝ տեմպը պահելու համար։
export const options = {
scenarios: {
browse: {
executor: "ramping-arrival-rate",
startRate: 10, timeUnit: "1s",
preAllocatedVUs: 50, maxVUs: 300,
stages: [
{ target: 100, duration: "3m" }, // ramp to 100 requests/s
{ target: 100, duration: "10m" }, // hold
{ target: 0, duration: "2m" }, // ramp down
],
},
},
thresholds: { "http_req_duration{scenario:browse}": ["p(95)<500"] },
};
04Իրատեսական օգտատիրոջ ճանապարհներ
Իրական օգտատերերը մուտք են գործում, դիտում, որոնում և checkout անում՝ քայլերի միջև դադարներով։ Մոդելավորեք հիմնական ճանապարհները analytics-ից վերցված իրական համամասնություններով (օրինակ՝ 80% դիտում, 15% որոնում, 5% checkout)։ Օգտագործեք group()՝ քայլերն անվանելու համար, tag-եր՝ մետրիկաները բաժանելու համար, և SharedArray՝ թեստային տվյալները մեկ անգամ բեռնելու և VU-ների միջև առանց memory պատճենելու կիսելու համար։ Որտեղ գրառումներ են լինում, ստեղծեք եզակի տվյալներ յուրաքանչյուր VU-ի և iteration-ի համար, որպեսզի չխփեք նույն տողին և արհեստական lock contention չստեղծեք։ Նախապատրաստումը (թեստային account-ի ստեղծում, token-ի ստացում) արեք setup()-ում, որը մեկ անգամ է աշխատում, և արդյունքը փոխանցեք VU-ներին։
import http from "k6/http";
import { group, check } from "k6";
import { SharedArray } from "k6/data";
const products = new SharedArray("products", () => JSON.parse(open("./products.json")));
const BASE = __ENV.BASE_URL || "https://staging.example.com";
export function setup() {
const res = http.post(BASE + "/api/login", JSON.stringify({ email: "[email protected]", password: __ENV.TEST_PASSWORD }),
{ headers: { "Content-Type": "application/json" } });
return { token: res.json("token") };
}
export default function (data) {
const params = { headers: { Authorization: "Bearer " + data.token } };
group("product page", () => {
const p = products[Math.floor(Math.random() * products.length)];
check(http.get(BASE + "/api/products/" + p.slug, params), { "200": (r) => r.status === 200 });
});
}
05Աշխատեցում, արդյունքների ընթերցում և CI
Աշխատեցրեք k6 run script.js տեղում կամ container-ում։ Վերջում k6-ը տպում է ամփոփում․ հարցումների տեմպ, latency percentile-ներ, error rate, փոխանցված տվյալներ և արդյոք յուրաքանչյուր threshold անցել է։ Նայեք p95-ին և p99-ին, ոչ թե միջիններին, քանի որ միջինները թաքցնում են դանդաղ պոչը, որը օգտատերերը նկատում են։ Տենդենցների և սերվերային մետրիկաների հետ համադրման համար արդյունքները stream արեք Prometheus (remote write) կամ Grafana Cloud k6 և դիտեք դրանք CPU-ի, database-ի և հերթերի dashboard-ների կողքին։ CI-ում յուրաքանչյուր release-ի ժամանակ staging-ի դեմ աշխատեցրեք կարճ smoke կամ average-load test, իսկ ավելի երկար stress և soak թեստերը պահեք ժամանակացույցով։ Երբեք load test մի արեք production-ը կամ third-party API առանց հստակ թույլտվության և պլանի։
# Local run with an environment variable
k6 run -e BASE_URL=https://staging.example.com script.js
# Docker, no local install
docker run --rm -i grafana/k6 run - <script.js
# Stream metrics to Prometheus remote write
K6_PROMETHEUS_RW_SERVER_URL=http://localhost:9090/api/v1/write \
k6 run -o experimental-prometheus-rw script.js
Օգտագործեք, երբ
- Launch-երից, ակցիաներից և կամպանիաներից առաջ՝ հաստատելու, որ համակարգը համապատասխանում է latency-ի և սխալների թիրախներին։
- Մեծ փոփոխություններից հետո (framework-ի նոր տարբերակ, database migration, caching շերտ)՝ performance regression-ները բռնելու համար։
- Capacity planning-ի համար՝ instance-ների չափերի, autoscaling threshold-ների և connection pool-ի սահմանների որոշման համար։
- Production-ի դանդաղումները անվտանգ միջավայրում վերարտադրելու և շտկելու համար։
Մի՛ օգտագործեք, երբ
- Որպես մեկ դանդաղ հարցման profiling-ի փոխարինող․ նախ օգտագործեք APM trace-եր կամ profiler։
- Production-ի կամ third-party ծառայությունների դեմ՝ առանց թույլտվության, ժամանակային պատուհանի և rollback պլանի։
- Staging միջավայրում, որն այնքան է տարբերվում production-ից, որ թվերը ոչինչ չեն նշանակում։
Այլընտրանքներ
- Apache JMeter
Հասուն Java գործիք՝ GUI-ով և բազմաթիվ protocol-ներով․ ավելի ծանր է, test plan-երը XML-ով են։
- Gatling
Կոդի վրա հիմնված թեստեր Java-ով, Kotlin-ով կամ Scala-ով (և JavaScript-ով), արդյունավետ engine և լավ հաշվետվություններ։
- Locust
Python-ի վրա հիմնված․ օգտատիրոջ վարքը գրում եք Python class-երով․ հեշտ է Python թիմերի համար։
- Artillery
YAML և JavaScript թեստեր, Node.js-ի վրա հիմնված, Playwright ինտեգրացիայով browser բեռի համար։
Լավագույն պրակտիկաներ
- Նախ սահմանեք հաջողությունը՝ թիրախային throughput, p95 և p99 latency և error rate՝ գրված որպես threshold-ներ։
- Capacity թեստերի համար օգտագործեք arrival-rate executor-ներ, որպեսզի դանդաղ պատասխանները չթաքցնեն խնդիրները։
- Մոդելավորեք իրական ճանապարհները և տրաֆիկի խառնուրդը analytics-ից՝ think time-ով և բազմազան թեստային տվյալներով։
- Թեստավորեք այնպիսի միջավայրում, որը չափով, կոնֆիգուրացիայով և տվյալների ծավալով արտացոլում է production-ը։
- Յուրաքանչյուր run-ի ընթացքում հետևեք թեստավորվող համակարգին (CPU, memory, database, հերթեր), ոչ միայն k6-ի ելքին։
- Յուրաքանչյուր release-ի ժամանակ CI-ում աշխատեցրեք կարճ smoke test, իսկ ավելի ծանր թեստերը՝ ժամանակացույցով։
- Համոզվեք, որ load generator-ն ինքը bottleneck չէ․ հետևեք դրա CPU-ին և ցանցին։
Տարածված սխալներ
- Պատասխանի միջին ժամանակը կարդալ p95-ի և p99-ի փոխարեն, ինչը թաքցնում է դանդաղ փորձառությունը։
- Մեկ URL-ի վրա հարձակվել առանց think time-ի և տվյալների բազմազանության, ուստի cache-երը ամեն ինչ արագ են ցույց տալիս։
- Load test անել laptop-ից տնային Wi-Fi-ով և չափել ցանցը սերվերի փոխարեն։
- Մոռանալ թեստային տվյալների մաքրումը՝ ընդհանուր միջավայրում թողնելով հազարավոր կեղծ պատվերներ կամ օգտատերեր։
- Աշխատեցնել production-ի դեմ՝ ոչ ոքի չզգուշացնելով, ինչը գործարկում է alert-ներ, rate limit-ներ կամ ծախսեր։
Խորը վերլուծություն
06Little-ի օրենքը և թեստի չափավորումը
Little-ի օրենքը կապում է երեք թիվ․ concurrency = throughput × համակարգում անցկացրած ժամանակ։ Եթե ձեզ պետք է 200 հարցում վայրկյանում, և հարցումը տևում է 0.25 վայրկյան, համակարգում միաժամանակ ընթացքի մեջ է մոտ 50 հարցում։ k6 arrival-rate թեստերի համար անհրաժեշտ VU-ները ≈ տեմպ × iteration-ի տևողություն (sleep-երով), ուստի 2 վայրկյանանոց ճանապարհը 50 iteration վայրկյանում տեմպով պահանջում է մոտ 100 VU․ maxVUs-ը սահմանեք պաշարով։ Նույն օրենքը բացատրում է սերվերի սահմանները․ 40 worker-ով PHP-FPM pool-ը 200 ms հարցումներով սահմանափակվում է մոտ 200 հարցում վայրկյանում, և դրանից վեր ամեն ինչ հերթագրվում է։ Եթե latency-ն թռչում է, մինչ throughput-ը հարթվում է, դուք ինչ-որ տեղ հասել եք concurrency-ի սահմանին․ worker pool, database connection-ներ կամ lock։
07Bottleneck-ի որոնումը թեստի ընթացքում
k6-ը ձեզ ասում է, որ ինչ-որ բան դանդաղ է․ սերվերային մետրիկաները ասում են՝ ինչու։ Հետևեք, այս հերթականությամբ, հավելվածի CPU-ին և worker-ների saturation-ին, database-ի CPU-ին, slow query log-ին և connection-ներին, cache hit ratio-ին, հերթի խորությանը և արտաքին API-ների latency-ին։ Յուրաքանչյուր ռեսուրսի համար օգտագործեք USE մեթոդը (utilisation, saturation, errors)։ k6-ում հարցումները tag արեք ըստ endpoint-ի անվան, որպեսզի ID-ներով URL-ները խմբավորվեն (օգտագործեք name tag-ը), և ամենադանդաղ endpoint-ները համադրեք ձեր APM-ի trace-երի հետ։ Շտկեք մեկ bottleneck միաժամանակ և նորից աշխատեցրեք նույն թեստը․ հաջորդ bottleneck-ը սովորաբար անմիջապես հայտնվում է։ Պահեք արդյունքների log՝ յուրաքանչյուր run-ի commit-ով, կոնֆիգուրացիայով և հիմնական թվերով, որպեսզի կարողանաք ազնվորեն համեմատել։
// Group dynamic URLs under one metric name
http.get(BASE + "/api/products/" + id, { tags: { name: "GET /api/products/:id" } });
// Custom metric for a business step
import { Trend } from "k6/metrics";
const checkoutTime = new Trend("checkout_duration", true);
checkoutTime.add(res.timings.duration);
08Coordinated omission և generator-ի սահմաններ
Coordinated omission-ը տեղի է ունենում, երբ load generator-ը սպասում է դանդաղ պատասխաններին՝ նախքան հաջորդ հարցումն ուղարկելը, ուստի ավելի քիչ հարցում է ուղարկում հենց այն ժամանակ, երբ համակարգը դժվարանում է, և չափված latency-ն ավելի լավ է թվում, քան իրականությունը։ Closed-model executor-ները նախագծով տառապում են դրանից։ Arrival-rate executor-ները խուսափում են դրա մեծ մասից՝ iteration-ները սկսելով ժամանակացույցով, բայց եթե VU-ները սպառվում են, k6-ը հաղորդում է dropped_iterations, որը պետք է դիտարկեք որպես ձախողման ազդանշան։ Հետևեք նաև generator-ին․ եթե դրա CPU-ն մոտ 80%-ից բարձր է, ժամանակաչափումները դառնում են անհուսալի։ Մեծ թեստերի համար բեռը բաշխեք մի քանի մեքենայի վրա Kubernetes-ում k6 Operator-ով կամ Grafana Cloud k6-ով, և բեռը ստեղծեք նույն տարածաշրջանից, որտեղ օգտատերերն են։
09Թեստավորում HTTP-ից այն կողմ՝ WebSockets, gRPC և extension-ներ
k6-ն ունի ներկառուցված module-ներ HTTP/1.1-ի և HTTP/2-ի, WebSockets-ի, gRPC-ի և browser-ի համար, իսկ extension-ները (կառուցված xk6-ով, իսկ նոր տարբերակներում պաշտոնականները լուծվում են ավտոմատ) ավելացնում են այնպիսի protocol-ներ, ինչպիսիք են Kafka-ն, SQL-ը կամ Redis-ը։ Սա թույլ է տալիս թեստավորել համակարգի այն մասերը, որոնց HTTP-ն չի հասնում․ WebSocket chat հազարավոր connection-ների տակ, gRPC service mesh կամ հերթի consumer-ի throughput-ը։ Այս թեստերին վերաբերվեք ինչպես HTTP-ին․ իրատեսական հաղորդագրությունների տեմպեր, threshold-ներ latency-ի և սխալների վրա և սերվերային մոնիտորինգ։ Event-driven համակարգերի համար չափեք end-to-end ժամանակը publish-ից մինչև արդյունք, ոչ միայն publish կանչը։
Իրական իրավիճակներ
Նախապատրաստում Black Friday ակցիային
Խնդիր
Օնլայն խանութը ակցիայի համար սպասում է իր սովորական տրաֆիկի տասնապատիկը։ Թիմը չգիտի, թե արդյոք ընթացիկ սերվերները, database-ը և վճարման հոսքը կդիմանան։
Ինչպես լուծել
Analytics-ից վերցրեք անցյալ տարվա գագաթը և տրաֆիկի խառնուրդը, բազմապատկեք սպասվող գործակցով և սահմանեք threshold-ներ․ p95-ը 800 ms-ից ցածր ապրանքի էջերի համար, 1.5 վ-ից ցածր checkout-ի համար, սխալները 1%-ից ցածր։ Գրեք scenario-ներ դիտման, որոնման, զամբյուղի և checkout-ի համար՝ ramping-arrival-rate executor-ով և վճարային պրովայդերի stub արված sandbox-ով։ Աշխատեցրեք production-ի չափի staging միջավայրի դեմ՝ անանունացված տվյալների պատճենով։ Շտկեք առաջին bottleneck-ը (հաճախ database query-ներ կամ connection pool-եր), նորից աշխատեցրեք և կրկնեք, մինչև թիրախներն անցնեն 30% պաշարով։ Ավարտեք spike test-ով և 2 ժամանոց soak-ով և համաձայնեցրեք մասշտաբավորման և rollback պլան։
Latency regression թարմացումից հետո
Խնդիր
Framework-ի և PHP-ի թարմացումից հետո օգտատերերը հաղորդում են, որ API-ն ավելի դանդաղ է թվում, բայց error log-երում ոչինչ ակնհայտ չի երևում։
Ինչպես լուծել
Գրեք կրկնվող average-load test տասը ամենածանրաբեռնված endpoint-ների համար՝ ֆիքսված տվյալներով և հաստատուն arrival rate-ով։ Աշխատեցրեք այն նախորդ և նոր release-ների դեմ նույնական ենթակառուցվածքի վրա, յուրաքանչյուրը երեք անգամ, և համեմատեք p95-ը յուրաքանչյուր endpoint-ի համար՝ name tag-երով։ Նայեք ամենամեծ փոփոխություն ունեցող endpoint-ներին և դրանց վրա օգտագործեք APM trace-եր կամ profiler։ Տարածված պատճառներն են անջատված OPcache-ը կամ caching-ը, dependency-ի բերած N+1 query-ները կամ փոխված connection կարգավորումները։ Շտկումից հետո CI-ում ավելացրեք threshold-ների վրա հիմնված smoke test, որպեսզի հաջորդ regression-ը ձախողի pipeline-ը, այլ ոչ թե հասնի օգտատերերին։
Load test-ը ցույց է տալիս հիանալի թվեր, production-ը՝ ոչ
Խնդիր
k6-ը հաղորդում է 80 ms p95 500 հարցում վայրկյանում, բայց production-ը դանդաղում է 200 հարցում վայրկյանում։
Ինչպես լուծել
Թեստը, հավանաբար, իրատեսական չէ։ Ստուգեք, արդյոք բոլոր VU-ները խփում են նույն մի քանի URL-ներին, որոնք տաք են մնում cache-ում, կամ նորից օգտագործում են մեկ user account։ Ավելացրեք բազմազան թեստային տվյալներ SharedArray-ից, տրաֆիկի իրական համամասնություններ և authenticated հոսքեր։ Համեմատեք staging-ը և production-ը․ database-ի չափ, index-ներ, cache-ի կոնֆիգուրացիա, CDN և worker-ների քանակ։ Օգտագործեք arrival-rate executor և ստուգեք dropped_iterations-ը։ Ներառեք ֆոնային բեռը, որը կա production-ում, օրինակ՝ cron job-եր և queue worker-ներ։ Ապա համեմատեք թեստի latency-ն յուրաքանչյուր endpoint-ի համար production-ի մետրիկաների հետ․ երբ դրանք համընկնում են ցածր բեռի դեպքում, մոդելը վստահելի է ավելի բարձր բեռների համար։
Արագ ուղեցույց
- Աշխատեցնել թեստ
k6 run script.js- Վերասահմանել VU-ները և տևողությունը
k6 run --vus 50 --duration 5m script.js- Փոխանցել environment variable
k6 run -e BASE_URL=https://staging.example.com script.js- Error rate-ի threshold
http_req_failed: ["rate<0.01"]- Latency-ի threshold
http_req_duration: ["p(95)<400", "p(99)<1000"]- Վաղ կանգնեցնել ձախողման դեպքում
{ threshold: "rate<0.05", abortOnFail: true }- Խմբավորել դինամիկ URL-ները
http.get(url, { tags: { name: "GET /api/items/:id" } })- Արտահանել ամփոփումը JSON-ով
k6 run --summary-export=summary.json script.js- Աշխատեցնել Docker-ում
docker run --rm -i grafana/k6 run - <script.js
Հարցեր և պատասխաններ
Q1Ո՞րն է տարբերությունը load, stress և soak testing-ի միջև։
Load test-ը ստուգում է համակարգը սպասվող տրաֆիկի տակ, օրինակ՝ սովորական օր կամ պլանավորված գագաթ, հաստատելու համար, որ այն համապատասխանում է latency-ի և սխալների թիրախներին։ Stress test-ը գնում է սպասվող տրաֆիկից այն կողմ՝ տեսնելու, թե ինչպես և որտեղ է համակարգը վատթարանում և արդյոք վերականգնվում է, երբ բեռը նվազում է։ Soak test-ը սովորական բեռը պահում է ժամերով՝ բացահայտելու դանդաղ խնդիրներ, ինչպիսիք են memory leak-երը, connection leak-երը, աճող հերթերը կամ լցվող սկավառակը։ Spike test-երը ավելացնում են կտրուկ թռիչք, իսկ breakpoint test-երը բեռը մեծացնում են մինչև ձախողում՝ առավելագույն capacity-ն գտնելու համար։ Յուրաքանչյուրը պատասխանում է տարբեր հարցի, ուստի ես ընտրում եմ ըստ այն ռիսկի, որը ցանկանում եմ նվազեցնել։
Q2Ինչո՞ւ նայել p95-ին և p99-ին միջինի փոխարեն։
Միջինները թաքցնում են պոչը։ Եթե 90 հարցում տևում է 100 ms, իսկ 10-ը՝ 3 վայրկյան, միջինը մոտ 390 ms է, ինչը ընդունելի է թվում, բայց տասից մեկ օգտատերը սպասում է երեք վայրկյան։ p95-ը ասում է, որ հարցումների 95%-ն ավելի արագ էր, քան այս արժեքը․ p99-ը ցույց է տալիս ամենավատ փորձառությունը, որին օգտատերերի մեծ մասը դեռ կհանդիպի։ Էջը հաճախ շատ հարցումներ է անում, ուստի էջի դիտման դանդաղ պոչին ընկնելու հավանականությունը շատ ավելի բարձր է, քան մեկ հարցման դեպքում։ Հետևաբար, թիրախները և alert-ները պետք է լինեն percentile-ների վրա՝ error rate-ի հետ միասին, իսկ միջինները օգտակար են միայն capacity-ի հաշվարկների համար։
Q3Ի՞նչ է virtual user-ը k6-ում։
Virtual user-ը կամ VU-ն անկախ կատարման համատեքստ է, որը ձեր default ֆունկցիան աշխատեցնում է ցիկլով, ինչպես համակարգն օգտագործող մոդելավորված մարդ։ Յուրաքանչյուր VU ունի իր փոփոխականները և cookie jar-ը, և VU-ները աշխատում են զուգահեռ։ VU-ների քանակը նույնը չէ, ինչ հարցումները վայրկյանում․ եթե յուրաքանչյուր iteration think time-ի հետ միասին տևում է երկու վայրկյան, 100 VU-ն տալիս է մոտ 50 iteration վայրկյանում։ Ահա թե ինչու կան arrival-rate executor-ներ․ դուք նշում եք նոր iteration-ների տեմպը, և k6-ը հատկացնում է այնքան VU, որքան պետք է։ k6-ը VU-ները արդյունավետ աշխատեցնում է Go-ում, ուստի մեկ մեքենան կարող է մոդելավորել հազարավորներ։
Q4Ինչպե՞ս օգտագործել threshold-ները CI-ում։
Threshold-ները pass/fail կանոններ են մետրիկաների վրա, օրինակ՝ http_req_failed rate-ը 1%-ից ցածր և http_req_duration p95-ը 400 միլիվայրկյանից ցածր։ Երբ որևէ threshold ձախողվում է, k6-ը դուրս է գալիս ոչ զրոյական կոդով, ուստի CI job-ը ձախողվում է ճիշտ ինչպես կոտրված unit test-ը։ Threshold-ները կարող եք սահմանափակել tag-երով, օրինակ՝ միայն checkout scenario-ն, և սահմանել abortOnFail՝ թեստը վաղ կանգնեցնելու համար, եթե սխալները պայթում են։ Pipeline-ում deployment-ից հետո staging-ի դեմ աշխատեցնում եմ կարճ թեստ՝ ծառայության նպատակների վրա հիմնված threshold-ներով, իսկ ավելի երկար թեստերը պահում եմ գիշերային ժամանակացույցով, որպեսզի հիմնական pipeline-ը արագ մնա։
Q5Ինչպե՞ս դարձնել load test-ը իրատեսական։
Սկսեք production-ի տվյալներից․ analytics-ը կամ access log-երը ցույց են տալիս, թե որ endpoint-ներն են օգտագործվում, ինչ համամասնություններով և ինչ գագաթնային տեմպով։ Մոդելավորեք հիմնական օգտատիրոջ ճանապարհները՝ քայլերի միջև think time-ով, և օգտագործեք բազմազան թեստային տվյալներ, օրինակ՝ տարբեր ապրանքներ, որոնման բառեր և օգտատերեր, որպեսզի cache-երը և database-ը վարվեն ինչպես իրականում։ Օգտագործեք open arrival-rate մոդել, որպեսզի օգտատերերը շարունակեն գալ, նույնիսկ եթե համակարգը դանդաղում է։ Աշխատեցրեք չափով և տվյալների ծավալով production-ին մոտ միջավայրի դեմ, ներառեք warm-up և թեստի ընթացքում հետևեք սերվերներին։ Վերջապես, համեմատեք թեստի latency profile-ը production-ի հետ՝ մոդելը վավերացնելու համար։
Q6Կարո՞ղ է k6-ը թեստավորել browser-ը և frontend-ի performance-ը։
Այո։ k6 browser module-ը կառավարում է իրական Chromium browser՝ Playwright-ին նման API-ով, ուստի կարող եք չափել Core Web Vitals, ինչպիսիք են LCP-ն և INP-ն, և թեստավորել օգտատիրոջ ճանապարհները browser-ում։ Browser թեստերը շատ ավելի ծանր են, քան protocol թեստերը․ մեկ browser VU-ն օգտագործում է այնքան ռեսուրս, որքան հարյուրավոր HTTP VU-ներ։ Տարածված հիբրիդ մոտեցումն այն է, որ բեռի մեծ մասը ստեղծվի թեթև HTTP scenario-ներով, և զուգահեռ աշխատեցվեն մի քանի browser VU՝ չափելու, թե ինչ են զգում իրական օգտատերերը այդ բեռի տակ։ Առանց բեռի մաքուր frontend performance-ի համար Lighthouse-ը կամ WebPageTest-ն ավելի պարզ գործիքներ են։
Սենիոր մակարդակի հարցեր
S1Ինչպե՞ս կներդնեիք performance testing-ը delivery pipeline-ում։
Կօգտագործեի տարբեր արժեքով շերտեր։ Յուրաքանչյուր merge-ի ժամանակ՝ մեկ-երկու րոպեանոց smoke test ephemeral կամ staging միջավայրի դեմ՝ հիմնական endpoint-ների error rate-ի և p95-ի threshold-ներով․ այն բռնում է կոտրված script-երը և մեծ regression-ները։ Գիշերը՝ average-load test սպասվող գագաթով, ֆիքսված տվյալների հավաքածուով, production-ի նման միջավայրում, արդյունքները պահված Prometheus-ում կամ Grafana Cloud k6-ում և համեմատված նախորդ run-երի հետ՝ alert-ով մոտ 10%-ից ավելի regression-ների դեպքում։ Մեծ launch-երից առաջ՝ stress, spike և soak թեստեր, որոնց հետևում են ինժեներները։ Script-երը գտնվում են repository-ում կոդի կողքին և review են արվում թեստերի պես։ Փոխզիջումը միջավայրի արժեքն է ընդդեմ վստահության․ ephemeral միջավայրերն օգնում են, բայց պետք է իրատեսական չափ ունենան, այլապես թվերը ստում են։
S2Ինչպե՞ս load test-ի արդյունքները վերածել capacity-ի և autoscaling-ի որոշումների։
Աշխատեցրեք աստիճանական arrival-rate test և յուրաքանչյուր քայլի համար գծեք throughput-ը, p95 latency-ն և ռեսուրսների օգտագործումը։ Կորի «ծունկը», որտեղ latency-ն կտրուկ աճում է, մինչ throughput-ը հարթվում է, մեկ instance-ի գործնական capacity-ն է․ ես պլանավորում եմ աշխատել դրա մոտ 60–70%-ով՝ spike-երը և խափանումները կլանելու համար։ Պարզեք, թե որ ռեսուրսն է առաջինը հագենում․ եթե դա CPU-ն է, autoscale արեք ըստ CPU-ի․ եթե database connection-ներն են, հավելվածի instance-ներ ավելացնելը վիճակն ավելի կվատացնի, ուստի նախ շտկեք pooling-ը կամ ավելացրեք read replica-ներ։ Autoscaler-ն ինքը թեստավորեք spike test-ով, քանի որ մասշտաբավորումը րոպեներ է տևում, և spike-ը մինչ այդ կարող է ավարտված լինել։ Վերջապես, ընտրված չափավորման համար հաշվարկեք հազար հարցման արժեքը, ինչը փոխզիջումը տեսանելի է դարձնում բիզնեսի համար։
S3Ինչո՞վ է տարբերվում event-driven կամ հերթերի վրա հիմնված համակարգի load testing-ը։
HTTP պատասխանն այլևս աշխատանքի ավարտը չէ։ API-ն կարող է 30 ms-ում պատասխանել 202 Accepted, մինչ job-ը րոպեներով մնում է հերթում, ուստի միայն հարցման latency-ն հիանալի է թվում, մինչ համակարգը հետ է մնում։ Ես չափում եմ end-to-end․ յուրաքանչյուր թեստային հաղորդագրություն tag եմ անում ID-ով և timestamp-ով, consumer-ը կամ probe-ը գրանցում է ավարտի ժամանակը, ապա թեստի ընթացքում հետևում եմ lag-ին և հերթի խորությանը։ Threshold-ները պետք է ընդգրկեն թե՛ API-ն, թե՛ մշակման ժամանակի նպատակը, օրինակ՝ պատվերների 95%-ը մշակված 30 վայրկյանում։ Թեստավորում եմ նաև consumer-ների մասշտաբավորումը և back-pressure-ը․ ինչ է տեղի ունենում, երբ downstream ծառայությունը դանդաղում է, և արդյոք կրկնումները ուժեղացնում են բեռը։ Այստեղ soak թեստերն ավելի կարևոր են, քանի որ backlog-երը դանդաղ են աճում։
Բառարան
- Virtual user (VU)
- Մոդելավորված օգտատեր, որը թեստային ֆունկցիան աշխատեցնում է ցիկլով՝ մյուսների հետ զուգահեռ։
- Iteration
- Default ֆունկցիայի մեկ ամբողջական աշխատեցում VU-ի կողմից։
- Executor
- k6-ի բաղադրիչ, որը scenario-ում պլանավորում է VU-ները և iteration-ները։
- Arrival rate
- Նոր iteration-ների սկսում ֆիքսված տեմպով՝ անկախ պատասխանի ժամանակից (open model)։
- Threshold
- Pass/fail կանոն մետրիկայի վրա․ դրա ձախողումը ստիպում է k6-ին դուրս գալ սխալով։
- Check
- Պատասխանի վրա assertion, որը հաշվվում է, բայց չի կանգնեցնում թեստը։
- p95 / p99
- Latency-ն, որից ցածր ավարտվել է հարցումների 95%-ը կամ 99%-ը։
- Soak test
- Երկար թեստ սովորական բեռով՝ leak-եր և ռեսուրսների դանդաղ սպառում գտնելու համար։
- Coordinated omission
- Չափման սխալ, երբ թեստավորողը դանդաղում է համակարգի հետ և թաքցնում իրական latency-ն։
Շարունակեք սովորել
Պրոդուկտի գաղափար ունե՞ք։Եկեք ստեղծենք այն։
Պատմեք ձեր գաղափարի, պրոդուկտի կամ թիմի մասին։ Սովորաբար պատասխանում եմ մեկ աշխատանքային օրվա ընթացքում։