ЁЯПЖ рдзрдбрд╛ 12 тАФ Load tests, budgets рдЖрдгрд┐ рд╕рдВрдкреВрд░реНрдг рдЪрд┐рддреНрд░: рдкрд╛рддреНрд░рддрд╛ рд╡реЗрд│рд╛
ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 12 ┬╖ рдорд╛рдЧреЗ: lesson-11-web-performance ┬╖ рд╢реЗрд╡рдЯрдЪрд╛ рдзрдбрд╛ ЁЯОУ
ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ
рдзрдбреЗ 01тАУ11, рдЖрдгрд┐ рддреЗ рд╡реЗрдЧрд╡рд╛рди рдареЗрд╡рдгреЗ: load test traffic рдЦрд╛рд▓реА latency рдХреБрдареЗ рд╡рд│рддреЗ (knee) рддреЗ
рд╢реЛрдзрддреЛ, рдЖрдгрд┐ CI рдордзреАрд▓ performance budget рдПрдЦрд╛рджреНрдпрд╛ рдмрджрд▓рд╛рдиреЗ рдЧреЛрд╖реНрдЯреА рдмрд┐рдШрдбрд▓реНрдпрд╛ рддрд░ build fail рдХрд░рддреЛ тАФ рдкреНрд░рддрд┐
page queries, bytes, LCP, p95. рдзрдбрд╛ рдХреЛрд░реНрд╕рдЪреНрдпрд╛ рд╕рдВрдкреВрд░реНрдг рдирдХрд╛рд╢рд╛рдиреЗ рд╕рдВрдкрддреЛ. perf/demo.py
рдордзреАрд▓ budgets() рдЖрдгрд┐ perf/sim.py рдордзреАрд▓ load_test рдЖрдгрд┐ check_budget.
ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ
рдЦрд▒реНрдпрд╛ рдХреНрд░реАрдбрд╛ рджрд┐рдирд╛рдЖрдзреА рд╢рд╛рд│рд╛ рдПрдХ рд░рдВрдЧреАрдд рддрд╛рд▓реАрдо рдШреЗрддреЗ. ЁЯПЯя╕П рддреЗ рдкрд╛рдгреНрдпрд╛рдЪреНрдпрд╛ рдЯреЗрдмрд▓рд╛рд╡рд░реВрди рдЕрдзрд┐рдХрд╛рдзрд┐рдХ рдзрд╛рд╡рдкрдЯреВ рдкрд╛рдард╡рддрд╛рдд, рддреЗ рдХреЗрд╡реНрд╣рд╛ рд╣рд│реВ рд╣реЛрддреЗ рд╣реЗ рдкрд╛рд╣рдгреНрдпрд╛рд╕рд╛рдареА.
- рд╕реЗрдХрдВрджрд╛рд▓рд╛ 50 рдзрд╛рд╡рдкрдЯреВ: рдареАрдХ, рдмрд╣реБрддреЗрдХ рдЬрдгреА рдХрд╛рд╣реА рдХреНрд╖рдгрдЪ рдерд╛рдВрдмрддрд╛рдд.
- рд╕реЗрдХрдВрджрд╛рд▓рд╛ 70: рдмрд╣реБрддреЗрдХреАрдВрд╕рд╛рдареА рдЕрдЬреВрдирд╣реА рдареАрдХ, рдкрдг рд╣рд│реВ рдЕрд╕рд▓реЗрд▓реНрдпрд╛ рдЬрд╛рд╕реНрдд рд╡реЗрд│ рдерд╛рдВрдмрддрд╛рдд.
- рд╕реЗрдХрдВрджрд╛рд▓рд╛ 90: рд░рд╛рдВрдЧ рд▓рд╛рдВрдм рд╣реЛрддреЗ.
- рд╕реЗрдХрдВрджрд╛рд▓рд╛ 110: рдЯреЗрдмрд▓ рд╣рд╛рддрд╛рд│реВ рд╢рдХрддреЗ рддреНрдпрд╛рдкреЗрдХреНрд╖рд╛ рдЬрд╛рд╕реНрдд. рд░рд╛рдВрдЧ рдлрдХреНрдд рд╡рд╛рдврддрдЪ рдЬрд╛рддреЗ. ЁЯШ╡
рдореНрд╣рдгреВрди рдЖрддрд╛ рддреНрдпрд╛рдВрдирд╛ рдорд╛рд╣реАрдд рдЖрд╣реЗ: 90 рдЪреНрдпрд╛ рдмрд▒реНрдпрд╛рдЪ рдЦрд╛рд▓реА рд░рд╛рд╣рд╛.
рдордЧ рджреАрдкрд┐рдХрд╛ рднрд┐рдВрддреАрд╡рд░ рдкрд╛рддреНрд░рддрд╛ рд╡реЗрд│рд╛ рд▓рд┐рд╣рд┐рддреЗ ЁЯУЭ: "рдирд┐рдХрд╛рд▓рд╛рдЪреЗ page office рдЪреНрдпрд╛ рдЬрд╛рд╕реНрддреАрдд рдЬрд╛рд╕реНрдд 5 рдлреЗрд▒реНрдпрд╛ рд╡рд╛рдкрд░реВ рд╢рдХрддреЗ. рддреЗ 2.5 рд╕реЗрдХрдВрджрд╛рдВрдкреЗрдХреНрд╖рд╛ рдХрдореА рд╡реЗрд│рд╛рдд рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ. рддреНрдпрд╛рдЪреЗ рд╡рдЬрди рдЬрд╛рд╕реНрддреАрдд рдЬрд╛рд╕реНрдд 500 KB рдЕрд╕реВ рд╢рдХрддреЗ." рдХреЛрдгреАрд╣реА рдирд┐рдХрд╛рд▓рд╛рдЪрд╛ program рдмрджрд▓рд▓рд╛ рдХреА рдкреНрд░рддреНрдпреЗрдХ рд╡реЗрд│реА рдПрдХ рдорджрддрдиреАрд╕ рдкрд╛рддреНрд░рддрд╛ рд╡реЗрд│рд╛ рддрдкрд╛рд╕рддреЗ. рдмрджрд▓рд╛рдиреЗ рддреНрдпрд╛рддрд▓реА рдПрдЦрд╛рджреА рдореЛрдбрд▓реА, рддрд░ рдорджрддрдиреАрд╕ рдХреНрд░реАрдбрд╛ рджрд┐рдирд╛рдЪреНрдпрд╛ рджрд░рдореНрдпрд╛рди рдирд╡реНрд╣реЗ, рддрд░ рдЖрдзреАрдЪ "рдирд╛рд╣реА тАФ рдкреБрдиреНрд╣рд╛ рдкреНрд░рдпрддреНрди рдХрд░рд╛" рдЕрд╕реЗ рд╕рд╛рдВрдЧрддреЗ. тЭМтЮбя╕ПтЬЕ
ЁЯЧ║я╕П рдЖрдХреГрддреА
flowchart LR
lt["ЁЯПЯя╕П load test, open model<br/>10 ms a request"] --> r50["50/s тЖТ p95 60 ms"]
r50 --> r70["70/s тЖТ p95 109 ms"]
r70 --> r90["90/s тЖТ p95 280 ms"]
r90 --> r110["110/s тЖТ p95 3122 ms<br/>above capacity"]
b["ЁЯУЭ budget: queries тЙд 5 ┬╖ LCP тЙд 2500 ms<br/>weight тЙд 500 KB ┬╖ p95 тЙд 100 ms"] --> before["before: 51 ┬╖ 5020 ┬╖ 2210 ┬╖ 109 тЖТ FAIL"]
b --> after["after: 1 ┬╖ 1055 ┬╖ 452.5 ┬╖ 23 тЖТ PASS"]
ЁЯЧ║я╕П рд░реЗрдЦрд╛рдЯрд▓реЗрд▓реА рдЖрд╡реГрддреНрддреА + рдПрдХ lab: https://school-edh.pages.dev/performance/lesson-diagrams.html#l12
тЭУ рдХрд╛рдп
- Load test тАФ рдирд┐рдпрдВрддреНрд░рд┐рдд рдкреНрд░рдорд╛рдгрд╛рдд traffic рдкрд╛рдард╡рд╛ рдЖрдгрд┐ latency percentiles, errors рдЖрдгрд┐ throughput рдореЛрдЬрд╛. рдкреНрд░рдХрд╛рд░: load (рдЕрдкреЗрдХреНрд╖рд┐рдд traffic), stress (рддреНрдпрд╛рдЪреНрдпрд╛ рдкрд▓реАрдХрдбреЗ, рдореЛрдбрдгреНрдпрд╛рдЪрд╛ рдмрд┐рдВрджреВ рд╢реЛрдзрдгреНрдпрд╛рд╕рд╛рдареА), spike (рдЕрдЪрд╛рдирдХ рдЙрдбреА), soak (рддрд╛рд╕рдиреН рддрд╛рд╕, leaks рдЖрдгрд┐ рд╣рд│реВ рд╡рд╛рдв рд╢реЛрдзрдгреНрдпрд╛рд╕рд╛рдареА).
- Knee тАФ рдЕрд╕рд╛ load рдЬрд┐рдереЗ latency рд╣рд│реВ рд╡рд╛рдврдгреЗ рдерд╛рдВрдмрд╡реВрди рд╡реЗрдЧрд╛рдиреЗ рд╡рд╛рдвреВ рд▓рд╛рдЧрддреЗ. рдзрдбрд╛ 09 рдЪреНрдпрд╛ рднрд╛рд╖реЗрдд, рдЬрд┐рдереЗ utilisation рдЬрд╛рд╕реНрдд рд╣реЛрддреЗ. рддреНрдпрд╛рдЪреНрдпрд╛ рдЦрд╛рд▓реА рдЪрд╛рд▓рд╡рдгреНрдпрд╛рдЪрд╛ рдЖрд░рд╛рдЦрдбрд╛ рдХрд░рд╛.
- Open рд╡рд┐рд░реБрджреНрдз closed model тАФ open load generator рдЙрддреНрддрд░реЗ рдХрд╛рд╣реАрд╣реА рдЕрд╕реЛрдд, рд╡реЗрд│рд╛рдкрддреНрд░рдХрд╛рдиреБрд╕рд╛рд░ requests рдкрд╛рдард╡рддреЛ (рдЦрд░реЗ users рдпреЗрддрд╛рдд рддрд╕реЗ). Closed generator рдкреБрдврдЪрд╛ request рдкрд╛рдард╡рдгреНрдпрд╛рдЖрдзреА рдкреНрд░рддреНрдпреЗрдХ рдЙрддреНрддрд░рд╛рдЪреА рд╡рд╛рдЯ рдкрд╛рд╣рддреЛ, рддреНрдпрд╛рдореБрд│реЗ server рд╣рд│реВ рдЭрд╛рд▓рд╛ рдХреА generator рд╕реБрджреНрдзрд╛ рд╣рд│реВ рд╣реЛрддреЛ рдЖрдгрд┐ test рджрд╛рд╡рд╛ рдХрд░рддреЛ рддреНрдпрд╛рдкреЗрдХреНрд╖рд╛ рдХрдореА load рдкрд╛рдард╡рддреЛ. рдпрд╛рддреВрди рд╣реЛрдгрд╛рд▒реНрдпрд╛ рдореЛрдЬрдорд╛рдкрд╛рдЪреНрдпрд╛ рдЪреБрдХреАрд▓рд╛ Gil Tene рдиреЗ coordinated omission рдЕрд╕реЗ рдирд╛рд╡ рджрд┐рд▓реЗ. Lab рдЪрд╛ load test open рдЖрд╣реЗ.
- Performance budget тАФ рдЕрд╢реА рдорд░реНрдпрд╛рджрд╛ рдЬреА рдмрджрд▓рд╛рдиреЗ рдореЛрдбрддрд╛ рдХрд╛рдорд╛ рдирдпреЗ: рдкреНрд░рддрд┐ page queries, page weight, bundle size, lab test рдордзрд▓рд╛ LCP, load test рдордзрд▓рд╛ p95. Budget "рд╡рд░реНрд╖рднрд░рд╛рдд рддреЗ рд╣рд│реВ рдЭрд╛рд▓реЗ" рдпрд╛рдЪреЗ рд░реВрдкрд╛рдВрддрд░ "рдпрд╛ commit рдиреЗ рддреЗ рд╣рд│реВ рдХреЗрд▓реЗ" рдордзреНрдпреЗ рдХрд░рддреЛ.
- CI рдордзреНрдпреЗ counts рд╡рд┐рд░реБрджреНрдз рд╡реЗрд│рд╛ тАФ shared CI machines рдЧреЛрдВрдЧрд╛рдЯрд╛рдЪреНрдпрд╛ (noisy) рдЕрд╕рддрд╛рдд (рдзрдбрд╛ 02), рддреНрдпрд╛рдореБрд│реЗ рддрд┐рдереЗ рд╡реЗрд│реЗрд╡рд░ рдЖрдзрд╛рд░рд┐рдд checks flaky рд╣реЛрддрд╛рдд рдХрд┐рдВрд╡рд╛ рддреНрдпрд╛рдВрдирд╛ рдореЛрдареА рд╕рд╡рд▓рдд рд▓рд╛рдЧрддреЗ. Counts тАФ queries, bytes, calls, allocations тАФ рдкреНрд░рддреНрдпреЗрдХ run рдордзреНрдпреЗ рд╕рд╛рд░рдЦреЗрдЪ рдЕрд╕рддрд╛рдд, рдореНрд╣рдгреВрди рддреЗ рдХрдбрдХ, рд╡рд┐рд╢реНрд╡рд╛рд╕рд╛рд░реНрд╣ gates рдмрдирддрд╛рдд. рд╡реЗрд│рд╛ рд╢рд╛рдВрдд, рдард░рд╛рд╡рд┐рдХ machine рд╡рд░, рд╕рд╛рдард╡рд▓реЗрд▓реНрдпрд╛ baseline рд╢реА рддреБрд▓рдирд╛ рдХрд░реВрди рддрдкрд╛рд╕рд╛рд╡реНрдпрд╛рдд.
ЁЯдФ рдХрд╛
рдХрд╛рд░рдг performance рд╢рд╛рдВрддрдкрдгреЗ рдЦрд╛рд▓рд╛рд╡рддреЗ. рдХреЛрдгреАрд╣реА рдореБрджреНрджрд╛рдо N+1 рдЬреЛрдбрдд рдирд╛рд╣реА; рддреЛ рдкреНрд░рддреНрдпреЗрдХ functional test рдкрд╛рд░ рдХреЗрд▓реЗрд▓реНрдпрд╛ рдЫреЛрдЯреНрдпрд╛ рдмрджрд▓рд╛рддреВрди рдпреЗрддреЛ. CI рдордзреАрд▓ budget рддреЛ рд▓рд┐рд╣рд┐рд▓рд╛ рдЧреЗрд▓рд╛ рддреНрдпрд╛рдЪ рджрд┐рд╡рд╢реА рдкрдХрдбрддреЛ, рдЬреЗрд╡реНрд╣рд╛ рдЙрдкрд╛рдп рдПрдХрд╛ рдУрд│реАрдЪрд╛ рдЕрд╕рддреЛ. рдЖрдгрд┐ рдореЛрдареНрдпрд╛ рджрд┐рд╡рд╕рд╛рдЖрдзреАрдЪрд╛ load test knee рдХреБрдареЗ рдЖрд╣реЗ рддреЗ рд╕рд╛рдВрдЧрддреЛ, рдЬреЗрд╡реНрд╣рд╛ рддреЛ рд╣рд▓рд╡рд╛рдпрд▓рд╛ рддреБрдордЪреНрдпрд╛рдХрдбреЗ рдЕрдЬреВрди рд╡реЗрд│ рдЕрд╕рддреЛ.
ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)
perf/sim.py рдордзреАрд▓ load_test(rates, service_ms, n, seed) рдкреНрд░рддреНрдпреЗрдХ rate рд╡рд░ рдзрдбрд╛ 09
рдЪреЗ simulate_queue (рдПрдХ server, random arrivals, open model) рдЪрд╛рд▓рд╡рддреЗ рдЖрдгрд┐ p50, p95 рдЖрдгрд┐ p99 рдкрд░рдд рджреЗрддреЗ.
check_budget(measured, budget) рдкреНрд░рддреНрдпреЗрдХ рдореЛрдЬрдорд╛рдкрд╛рдЪреА рддреНрдпрд╛рдЪреНрдпрд╛ рдорд░реНрдпрд╛рджреЗрд╢реА рддреБрд▓рдирд╛ рдХрд░рддреЗ рдЖрдгрд┐ rows рдЖрдгрд┐ рдПрдХреВрдг
pass/fail рдкрд░рдд рджреЗрддреЗ. perf/demo.py рдордзреАрд▓ budgets() "before" values рдЖрдзреАрдЪреНрдпрд╛
рдзрдбреНрдпрд╛рдВрдордзреВрди live рдореЛрдЬрддреЗ тАФ рдзрдбрд╛ 07 рдЪреНрдпрд╛ N+1 рдордзреАрд▓ query count, рдзрдбрд╛ 11 рдордзрд▓реЗ LCP рдЖрдгрд┐ bytes тАФ рдЖрдгрд┐
"after" values рддреНрдпрд╛рдВрдЪреНрдпрд╛ рдЙрдкрд╛рдпрд╛рдВрдордзреВрди. "After" p95 рдЕрд╕реЗ рдЧреГрд╣реАрдд рдзрд░рддреЛ рдХреА profile рдХрд░реВрди рдХреЗрд▓реЗрд▓реНрдпрд╛ рдЙрдкрд╛рдпрд╛рдиреЗ
service time 10 ms рд╡рд░реВрди 5 ms рд╡рд░ рдЖрдгрд▓рд╛: рд╣реЗ model рдЪреЗ рдПрдХ input рдЖрд╣реЗ.
ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛
python3 perf/demo.py budgets
python3 - <<'EOF'
import sys; sys.path.insert(0, "perf"); from sim import load_test, check_budget
for r, p50, p95, p99 in load_test((60, 80, 95), service_ms=5.0):
print(f"service 5 ms, {r} req/s тЖТ p95 {p95} ms")
rows, ok = check_budget({"SQL queries per page": 7, "page weight KB": 480}, {"SQL queries per page": 5, "page weight KB": 500})
for name, value, limit, good in rows: print(f"{name}: {value} / {limit} {'ok' if good else 'OVER'}")
print("PASS" if ok else "FAIL")
sys.exit(0 if ok else 1)
EOF
echo "exit code: $?"
python3 perf/demo.py
python3 perf/test_perf.py
тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ
budgets рд╣реЗ рдЫрд╛рдкрддреЗ:
тФАтФА a load test (simulated, open model): one server, 10 ms per request, capacity about 100 requests/s
50 req/s тЖТ p50 14 ms ┬╖ p95 60 ms ┬╖ p99 98 ms
70 req/s тЖТ p50 25 ms ┬╖ p95 109 ms ┬╖ p99 160 ms
90 req/s тЖТ p50 64 ms ┬╖ p95 280 ms ┬╖ p99 411 ms
110 req/s тЖТ p50 1716 ms ┬╖ p95 3122 ms ┬╖ p99 3187 ms
the knee: past about 80% busy, p95 climbs fast ┬╖ above capacity the queue only grows
тФАтФА budget check, before the fixes: SQL queries per page 51 / 5 тЭМ ┬╖ LCP ms (simulated) 5020 / 2500 тЭМ ┬╖ page weight KB 2210 / 500 тЭМ ┬╖ p95 ms at 70 req/s 109 / 100 тЭМ тЖТ FAIL (the CI job exits 1)
тФАтФА budget check, after the fixes : SQL queries per page 1 / 5 тЬЕ ┬╖ LCP ms (simulated) 1055 / 2500 тЬЕ ┬╖ page weight KB 452.5 / 500 тЬЕ ┬╖ p95 ms at 70 req/s 23 / 100 тЬЕ тЖТ PASS
рддреБрдордЪрд╛ snippet рд╣реЗ рдЫрд╛рдкрддреЛ:
service 5 ms, 60 req/s тЖТ p95 22 ms
service 5 ms, 80 req/s тЖТ p95 25 ms
service 5 ms, 95 req/s тЖТ p95 28 ms
SQL queries per page: 7 / 5 OVER
page weight KB: 480 / 500 ok
FAIL
exit code: 1
рдкреВрд░реНрдг demo тЬЕ done тАФ every runner timed, the relay is faster рдиреЗ рд╕рдВрдкрддреЛ, рдЖрдгрд┐ tests
12/12 passed рдиреЗ.
ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ
50 рд╡рд░реВрди 90 requests/s (1.8├Ч load) рд╡рд░, p95 60 рд╡рд░реВрди 280 ms рд╡рд░ рдЧреЗрд▓рд╛ (4.7├Ч); 110/s рд╡рд░, capacity рдЪреНрдпрд╛ рдкрд▓реАрдХрдбреЗ, рддреЛ 3 рд╕реЗрдХрдВрдж рдУрд▓рд╛рдВрдбреВрди рдЧреЗрд▓рд╛ рдЖрдгрд┐ рддрд░реАрд╣реА рд╡рд╛рдврддрдЪ рд╣реЛрддрд╛. Service time рдЕрд░реНрдзрд╛ рдХреЗрд▓реНрдпрд╛рдиреЗ knee рд╣рд▓рд▓рд╛: 95 requests/s рд╡рд░ p95 рдлрдХреНрдд 28 ms рд╣реЛрддрд╛. Budget рдиреЗ "before" build рд▓рд╛ рдЪрд╛рд░рд╣реА rows рд╡рд░ fail рдХреЗрд▓реЗ рдЖрдгрд┐ "after" build pass рдХреЗрд▓реЗ. рдЖрдгрд┐ рдорд░реНрдпрд╛рджреЗрдкрд▓реАрдХрдбреЗ рдЧреЗрд▓реЗрд▓реА рдПрдХрдЪ row тАФ 5 рдЪреНрдпрд╛ budget рд╡рд┐рд░реБрджреНрдз 7 queries тАФ script рд▓рд╛ exit 1 рдХрд░рд╛рдпрд▓рд╛ рдкреБрд░реЗрд╢реА рд╣реЛрддреА, рдЖрдгрд┐ CI job рд▓рд╛рд▓ рд╣реЛрдгреНрдпрд╛рд╕рд╛рдареА рдПрд╡рдвреЗрдЪ рд▓рд╛рдЧрддреЗ.
тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛
- closed model рдиреЗ load testing рдХрд░реВрди latencies рдЦрд▒реНрдпрд╛ users рдЪреНрдпрд╛ рдЕрд╕рд▓реНрдпрд╛рд╕рд╛рд░рдЦреНрдпрд╛ рд╕рд╛рдВрдЧрдгреЗ
- рдПрдХрд╛рдЪ laptop рд╡рд░реВрди load testing, рдЬреНрдпрд╛рдЪреЗ CPU рдХрд┐рдВрд╡рд╛ connections server рдЪреНрдпрд╛ рдЖрдзреАрдЪ рд╕рдВрдкрддрд╛рдд
- рдЕрдЧрджреА рд▓рд╣рд╛рди database рдЕрд╕рд▓реЗрд▓реНрдпрд╛ staging system рд╡рд░ test рдХрд░рдгреЗ тАФ plans (рдзрдбрд╛ 10) рдЖрдгрд┐ caches рд╡реЗрдЧрд│реЗ рдЕрд╕рддрд╛рдд
- рдлрдХреНрдд mean рд╕рд╛рдВрдЧрдгрд╛рд░рд╛ load test (рдзрдбрд╛ 01)
- shared CI runners рд╡рд░ рдШрдЯреНрдЯ рдорд░реНрдпрд╛рджрд╛рдВрд╕рд╣ рд╡реЗрд│реЗрд╡рд░ рдЖрдзрд╛рд░рд┐рдд budgets тАФ flaky builds, рдордЧ рджреБрд░реНрд▓рдХреНрд╖рд┐рдд builds
- рдЬреНрдпрд╛рдЪреА рдЬрдмрд╛рдмрджрд╛рд░реА рдХреЛрдгрд╛рдЪреАрдЪ рдирд╛рд╣реА рдЕрд╕рд╛ budget: рддреЛ fail рдЭрд╛рд▓рд╛ рдХреА code рджреБрд░реБрд╕реНрдд рдХрд░рдгреНрдпрд╛рдРрд╡рдЬреА рдорд░реНрдпрд╛рджрд╛ рд╡рд╛рдврд╡рд▓реА рдЬрд╛рддреЗ
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд
рдЦрд▒реНрдпрд╛ account рд╡рд░ тАФ open-model executor рдЖрдгрд┐ run fail рдХрд░рдгрд╛рд▒реНрдпрд╛ thresholds рд╕рд╣ k6 load test (threshold fail рдЭрд╛рд▓реНрдпрд╛рд╕ k6 non-zero exit рдХрд░рддреЛ):
import http from 'k6/http';
export const options = {
scenarios: { steady: { executor: 'constant-arrival-rate', rate: 70, timeUnit: '1s',
duration: '5m', preAllocatedVUs: 50, maxVUs: 200 } },
thresholds: { http_req_duration: ['p(95)<100'], http_req_failed: ['rate<0.01'] },
};
export default function () { http.get('https://staging.results.school.example/results'); }
k6 run results-load.js
рд╕рд╛рдзреНрдпрд╛ test рд╕рд╛рд░рдЦрд╛ query-count budget (Django):
class ResultsPageBudget(TestCase):
def test_results_page_queries(self):
make_runners(50)
with self.assertNumQueries(2): # fails if an N+1 sneaks back in
self.client.get("/results/")
рдкреНрд░рддреНрдпреЗрдХ pull request рд╡рд░ budgets рдЪрд╛рд▓рд╡рдгрд╛рд░рд╛ GitHub Actions job, рдЖрдгрд┐ page рд╕рд╛рдареА Lighthouse CI:
name: performance-budgets
on: [pull_request]
jobs:
budgets:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: "3.12" }
- run: pip install -r requirements.txt
- run: python manage.py test budgets # query counts, response sizes
- run: npx @lhci/cli autorun # LCP, bytes, CLS against lighthouserc.json assertions
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: рдкреБрдврдЪреНрдпрд╛ feature рдЖрдзреА budget рд▓рд┐рд╣реВрди рдареЗрд╡рд╛, count рд╡рд░ рдЖрдзрд╛рд░рд┐рдд рднрд╛рдЧ рдЖрдЬрдЪ CI рдордзреНрдпреЗ рдШрд╛рд▓рд╛, рдЖрдгрд┐ рдкреНрд░рддреНрдпреЗрдХ рдореЛрдареНрдпрд╛ рдХрд╛рд░реНрдпрдХреНрд░рдорд╛рдЖрдзреА рддреБрдордЪреНрдпрд╛ рд╕рд░реНрд╡рд╛рдд busy рддрд╛рд╕рд╛рдЪреНрдпрд╛ 1.5тАУ2├Ч рд╡рд░ load test рдЪрд╛рд▓рд╡рд╛. рдЬрд┐рдереЗ CI рдордзреНрдпреЗ рд╡реЗрд│ рддрдкрд╛рд╕рд╛рд╡реА рд▓рд╛рдЧрддреЗ, рддрд┐рдереЗ рддреНрдпрд╛рдЪ machine рд╡рд░рдЪреНрдпрд╛ baseline рд╢реА рддреБрд▓рдирд╛ рдХрд░рд╛, рдХрд┐рдВрд╡рд╛ рддреНрдпрд╛рдРрд╡рдЬреА CPU instructions рдореЛрдЬрд╛ (Cachegrind-рдЖрдзрд╛рд░рд┐рдд tools рд╣реЗ рдХрд░рддрд╛рдд).
ЁЯОУ рдХреНрд░реАрдбрд╛ рджрд┐рди рд╕рдВрдкрд▓рд╛
рд╕реНрдЯреЙрдкрд╡реЙрдЪ mean рдирд╡реНрд╣реЗ рддрд░ percentiles рд╕рд╛рдВрдЧрддрд╛рдд тЖТ benchmark warm up рд╣реЛрддреЛ, рдкреБрдирд░рд╛рд╡реГрддреНрддреА рдХрд░рддреЛ рдЖрдгрд┐ рддреНрдпрд╛рдЪрд╛ рдкрд╕рд╛рд░рд╛ рджрд╛рдЦрд╡рддреЛ тЖТ рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдХреЗрдЪрд╛ clipboard hot spot рд╢реЛрдзрддреЛ тЖТ рдпреЛрдЧреНрдп algorithm рд╡рдХреНрд░ рдмрджрд▓рддреЛ тЖТ generators рдПрдХрд╛ рд╡реЗрд│реА рдПрдХрдЪ рдЕрдбрдерд│рд╛ рдзрд░рддрд╛рдд тЖТ scoreboard рд▓рдХреНрд╖рд╛рдд рдареЗрд╡рддреЛ, рдЖрдгрд┐ рддреНрдпрд╛рдЪрд╛ hit ratio рдХрд┐рддреА рддреЗ рд╕рд╛рдВрдЧрддреЛ тЖТ рдкреНрд░рддреНрдпреЗрдХ рдмреЕрдЯрди-рдмрджрд▓рд╛рд▓рд╛ рдПрдХ рдлреЗрд░реА рд▓рд╛рдЧрддреЗ, рдореНрд╣рдгреВрди batch рдХрд░рд╛ тЖТ рд╡рд╛рдЯ рдкрд╛рд╣рдгреЗ overlap рд╣реЛрддреЗ, Python рдХрд╛рдорд╛рд▓рд╛ рдмреЕрдЯрди рд▓рд╛рдЧрддреЗ тЖТ 100% busy рдЬрд╡рд│ рдкрд╛рдгреНрдпрд╛рдЪреНрдпрд╛ рдЯреЗрдмрд▓рд╛рд╡рд░рдЪреА рдкреНрд░рддреАрдХреНрд╖рд╛ рд╕реНрдлреЛрдЯрдХ рд╡рд╛рдврддреЗ, рдЖрдгрд┐ рд╕рд░реНрд╡рд╛рдд рд╣рд│реВ рдЯрдкреНрдкрд╛ рд░рд┐рд▓реЗрд▓рд╛ рдорд░реНрдпрд╛рджрд╛ рдШрд╛рд▓рддреЛ тЖТ index 10,000 рд╡рд╛рдЪрдгреНрдпрд╛рдРрд╡рдЬреА 20 рдкрддреНрд░рдХреЗ рд╢реЛрдзрддреЛ тЖТ page рдЪреЗ рдореВрд▓реНрдпрдорд╛рдкрди рдкрд╛рд▓рдХрд╛рдВрдЪреНрдпрд╛ phone рд╡рд░ рд╣реЛрддреЗ тЖТ рдЖрдгрд┐ CI рдордзреАрд▓ рдкрд╛рддреНрд░рддрд╛ рд╡реЗрд│рд╛ рд╣реЗ рд╕рдЧрд│реЗ рд╡реЗрдЧрд╡рд╛рди рдареЗрд╡рддрд╛рдд. рддреБрдореНрд╣реА рдлрдХреНрдд performance рдЪреНрдпрд╛ рдпреБрдХреНрддреНрдпрд╛ рд╢рд┐рдХрд▓реНрдпрд╛ рдирд╛рд╣реАрдд тАФ рддреБрдореНрд╣реА рдХреЛрдгрддрд╛рд╣реА рд╣рд│реВ program рдШреЗрдКрди, рддреЛ рдореЛрдЬреВрди, рдорд╣рддреНрддреНрд╡рд╛рдЪреА рдПрдХрдЪ рдЧреЛрд╖реНрдЯ рд╢реЛрдзреВрди, рддреА рджреБрд░реБрд╕реНрдд рдХрд░реВрди, рддреА рджреБрд░реБрд╕реНрддрдЪ рд░рд╛рд╣рд┐рд▓реА рд╣реЗ рд╕рд┐рджреНрдз рдХрд░реВ рд╢рдХрддрд╛. ЁЯПОя╕ПЁЯПЖЁЯОУ
тПня╕П рдкреБрдвреЗ
рдЗрддрд░ рд╢рд╛рд│рд╛. Scaling school рдПрдХ machine рдкреБрд░реЗрд╢реА рдирд╕реЗрд▓ рддреЗрд╡реНрд╣рд╛ machines рдЬреЛрдбрддреЗ; Observability school production рдордзрд▓реЗ percentiles рдЖрдгрд┐ traces рдЧреЛрд│рд╛ рдХрд░рддреЗ; Database school queries рдордзреНрдпреЗ рдЕрдзрд┐рдХ рдЦреЛрд▓рд╡рд░ рдЬрд╛рддреЗ; DSA school algorithms рдордзреНрдпреЗ; School portal рдордзреНрдпреЗ рдмрд╛рдХреА рд╕рдЧрд│реЗ рдЖрд╣реЗ.
git checkout main
python3 perf/demo.py # one last run, for fun