Przejdź do głównej zawartości

Testy obciążenia, stresu i benchmarków

Testowanie wydajności mierzy, jak system zachowuje się pod obciążeniem: k6 i Artillery symulują realistyczny ruch, zwiększają liczbę wirtualnych użytkowników do punktu załamania i oblewają przebieg na jawnych progach. AI generuje skrypty, czyta podsumowanie razem z logiem wolnych zapytań, by uszeregować wąskie gardła, i wpina bramkę regresji w CI.

Twoje API obsługuje 500 zapytań na sekundę na stagingu i wszyscy świętują. Potem przychodzi Black Friday, ruch skacze do 3000 rps, a pula połączeń z bazą danych wyczerpuje się w ciągu minut. Latencja p95 skacze ze 120 ms do 4 s, wykres czasu odpowiedzi wygląda jak kij hokejowy i nikt nie potrafi wskazać zmiany, która to spowodowała.

Potrzebujesz testu obciążenia, który odtworzy ten skok, odczytu, która warstwa nasyca się jako pierwsza, oraz bramki regresji w CI, żeby kolejny deploy nie zaskoczył cię o 21:00. Ten przewodnik prowadzi tę pętlę z pomocą AI: wygeneruj realistyczny skrypt, uruchom go, daj modelowi przeczytać wynik i log wolnych zapytań, a potem wepnij bramkę progową do pipeline’u. Te same prompty działają w Cursorze, Claude Code i Codeksie — różni się tylko sposób uruchamiania każdego narzędzia.

  • Oficjalny serwer MCP k6 (grafana/mcp-k6) wpięty we wszystkie trzy narzędzia, plus k6 x agent init do bootstrapu jedną komendą
  • Gotowe prompty generujące uruchamialne skrypty k6: narastanie typu flash sale, test stresu per endpoint znajdujący punkt załamania oraz smoke test poniżej 60 sekund
  • Dwa prompty analityczne — jeden czyta tabelę krzywej obciążenia, drugi podsumowanie k6 wraz z logiem wolnych zapytań Postgresa — i produkuje uszeregowaną listę wąskich gardeł „najpierw najważniejsze”
  • Prompt Playwright + Lighthouse, który mierzy Core Web Vitals (LCP, INP, CLS) pod równoległym obciążeniem
  • Benchmarki bazy danych porównujące zapytanie z indeksem i bez niego, przy produkcyjnej liczbie wierszy
  • Dwie bramki CI wyłapujące różne regresje: progi bezwzględne przez kody wyjścia k6 run oraz porównanie z bazą odniesienia oblewające PR przy zjeździe p95 o 20%
  • Tryby awarii, które sprawiają, że liczby z testów obciążenia kłamią — i jak je wyłapać, zanim zaufasz dashboardowi

Na wierzchu warto zainstalować oficjalny serwer MCP k6 od Grafany (grafana/mcp-k6). Pozwala on agentowi walidować skrypty, uruchamiać testy i czytać dokumentację k6 bez przeklejania outputu CLI w tę i z powrotem. Dostarczany jest jako binarka Go lub obraz Dockera — nie jako pakiet npm, więc zignoruj wszelkie „k6 MCP” oparte na npx, które znajdziesz; to nieoficjalne nakładki.

Najszybsza droga to k6 x agent init (wymaga k6 v2.0+ na PATH), które wrzuca odpowiednie pliki skilli do twojego edytora i rejestruje serwer MCP dla narzędzia, którego używasz:

Okno terminala
# Bootstrap k6 skills + MCP config for one editor...
k6 x agent init claude-code # or cursor, codex
# ...or wire up every supported editor at once
k6 x agent init --all

Jeśli wolisz wpiąć serwer MCP ręcznie, instalacja jest identyczna we wszystkich narzędziach — różni się tylko komenda rejestracji.

Zainstaluj binarkę, a następnie dodaj ją w Settings → MCP → Add, podając mcp-k6 jako komendę (stdio). Albo wrzuć to do .cursor/mcp.json:

{
"mcpServers": {
"k6": { "command": "mcp-k6" }
}
}

Najpierw zainstaluj binarkę: brew tap grafana/grafana && brew install mcp-k6 (lub docker pull grafana/mcp-k6:latest).

Do wydajności po stronie przeglądarki przyda ci się też Playwright MCP (@playwright/mcp), którego konfiguracja jest taka sama w każdym narzędziu:

Okno terminala
claude mcp add playwright -- npx -y @playwright/mcp@latest

W Cursorze dodaj go przez Settings → MCP; w Codeksie dodaj blok [mcp_servers.playwright] wskazujący na tę samą komendę npx.

Pętla jest taka sama w każdym narzędziu. Zmienia się sposób wywołania.

  1. Wygeneruj skrypt na podstawie prawdziwego endpointu, docelowej liczby VU, profilu narastania i jawnych progów — a nie „napisz test obciążenia”.
  2. Uruchom go względem stagingu (k6 run script.js), gdzie serwer MCP pozwala agentowi bezpośrednio wykonywać go i czytać output.
  3. Przeanalizuj wyniki, przekazując modelowi podsumowanie k6 oraz log wolnych zapytań i prosząc o uszeregowaną listę wąskich gardeł.
  4. Wepnij bramkę w CI, żeby regresja p95 oblała build, zanim trafi na produkcję.

Oto jak odpalić kroki 1 i 2 w każdym narzędziu:

Otwórz panel agenta (Cmd+I), wklej prompt generujący i pozwól mu napisać tests/load/checkout.js. Z podłączonym serwerem MCP k6 agent może sam uruchomić k6 run i iterować nad oblanymi progami w trybie inline. Użyj checkpointu przed przebiegiem, żeby móc wycofać skrypt, jeśli wygenerowany profil VU jest nierealistyczny.

Po prompt na pojedynczy endpoint sięgasz jako pierwszy: daje skrypt, który przeczytasz w minutę i któremu zaufasz, bo każda liczba w nim jest liczbą, którą sam podałeś.

Wygenerowany skrypt powinien wyjść mniej więcej tak — konkretne etapy VU i progi, a nie szkielet ścieżki happy path:

import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
stages: [
{ duration: '2m', target: 200 }, // ramp to peak
{ duration: '5m', target: 200 }, // hold
{ duration: '1m', target: 0 }, // ramp down
],
thresholds: {
http_req_duration: ['p(95)<300', 'p(99)<800'],
http_req_failed: ['rate<0.01'],
},
};
export default function () {
const res = http.post(`${__ENV.STAGING_URL}/api/checkout`, JSON.stringify({
cartId: 'c_load_test', paymentMethod: 'pm_test',
}), { headers: { 'Content-Type': 'application/json' } });
check(res, { 'status is 200': (r) => r.status === 200 });
sleep(1); // think time so 200 VUs != 200 RPS
}

k6 run kończy się kodem niezerowym, gdy próg zostaje przekroczony, i to właśnie sprawia, że bramka CI poniżej jest banalnie prosta.

Jeden endpoint to początek; prawdziwy przepływ to kilka, a kształt ruchu ma znaczenie nie mniejsze niż jego wolumen. Te trzy prompty skalują ten sam przepis w górę — wieloetapowa podróż użytkownika ze skokiem, cały zestaw z helperami i skryptami npm oraz przebieg po całym repozytorium, który sam wybiera endpointy.

Generate a k6 load test for our checkout API:
Scenario: Simulate a flash sale with ramping traffic
- Ramp from 0 to 100 virtual users over 2 minutes
- Hold at 100 VUs for 5 minutes (steady state)
- Spike to 500 VUs for 1 minute (flash sale moment)
- Return to 100 VUs for 2 minutes (recovery)
- Ramp down to 0 over 1 minute
API calls per virtual user iteration:
1. POST /api/auth/login (use test credentials from env)
2. GET /api/products?category=sale (browse sale items)
3. POST /api/cart/items (add random product)
4. POST /api/checkout (complete purchase with test payment)
Thresholds:
- p95 response time < 500ms during steady state
- p99 response time < 2000ms during spike
- Error rate < 1% at all times
- Checkout success rate > 99%
Save to /tests/performance/checkout-load.k6.js

Test obciążenia pyta „czy wytrzyma przy ruchu, jakiego się spodziewamy?”. Test stresu pyta „przy jakiej liczbie przestaje wytrzymywać?” — a odpowiedź trafia do dokumentu planowania pojemności. Zdefiniuj punkt załamania przed przebiegiem, żeby test raportował liczbę, a nie wrażenie.

Czerwony próg mówi, że coś jest wolne. Nie mówi, która warstwa się nasyciła, a to właśnie pytanie warto oddać modelowi. Dwa prompty, zależnie od tego, jakim materiałem dysponujesz.

Gdy masz tylko krzywą obciążenia, samym dowodem jest kształt degradacji — czyste liniowe narastanie wskazuje na coś zupełnie innego niż urwisko:

Gdy możesz dołożyć log wolnych zapytań bazy z tego samego okna, diagnoza przestaje być wnioskowaniem. Ten drugi prompt wymaga dowodu przy każdym twierdzeniu i kończy się jedną priorytetową zmianą, a nie listą możliwości:

Żeby pójść dalej, podłącz Sentry MCP, aby agent mógł skorelować przekroczenia progów z błędami i wolnymi transakcjami, które Sentry zarejestrował podczas przebiegu. Zdalny serwer to najprostsza konfiguracja i jest identyczny we wszystkich narzędziach:

Okno terminala
# Official Sentry remote MCP (recommended)
claude mcp add --transport http sentry https://mcp.sentry.dev/mcp
# Local stdio alternative, if you need it
claude mcp add sentry -- npx -y @sentry/mcp-server

Potem zapytaj: „Dla okna testu obciążenia 14:00–14:08 UTC wyciągnij najwolniejsze transakcje i wszelkie nowe błędy z Sentry i zestaw je z przekroczeniami progów k6.” To zamienia czerwony przebieg CI w konkretną listę transakcji do naprawy.

Serwerowe p95 może być zdrowe, a strona i tak sprawiać wrażenie zepsutej, bo przeglądarka wykonuje pracę, której API nigdy nie widzi. Mierz front end, gdy API jest pod obciążeniem, a nie na bezczynnej maszynie.

Większość urwisk w testach obciążenia okazuje się zapytaniem, które było w porządku przy skali danych zaseedowanych. Benchmarkuj zapytania bezpośrednio, przy produkcyjnej liczbie wierszy, z indeksem, o który się spierasz, i bez niego.

Dwie bramki wyłapują dwie różne awarie i chcesz mieć obie. Pierwsza jest bezwzględna: thresholds w samym skrypcie definiują „za wolno”, a ponieważ k6 run zwraca niezerowy kod wyjścia, gdy któryś próg zostanie przekroczony, krok CI sprowadza się do uruchomienia skryptu — bez własnej logiki porównań. Użyj oficjalnej grafana/setup-k6-action, a nie ręcznie sklejonej instalacji przez curl:

.github/workflows/load-test.yml
- uses: actions/checkout@v5
- uses: grafana/setup-k6-action@v1
- run: k6 run tests/load/checkout.js
env:
STAGING_URL: ${{ secrets.STAGING_URL }}
TOKEN: ${{ secrets.LOAD_TEST_TOKEN }}

Druga bramka jest względna i wyłapuje to, czego pierwsza nie potrafi: zmiana, która podwaja p95 z 90 ms do 180 ms, przechodzi próg p(95)<300, po cichu zjadając połowę twojego zapasu. Do tego potrzebujesz zapisanej bazy odniesienia i porównania procentowego.

Uruchomienia testów obciążenia i stresu są długie i głodne CPU, więc to, gdzie je uruchamiasz, ma znaczenie nie mniejsze niż sam skrypt. Każde narzędzie ma naturalne miejsce dla zadań k6:

Pisz i debuguj skrypty k6 lokalnie w trybie Agent na URL stagingowym, a potem zacommituj plik workflow. Cursor to miejsce, gdzie iterujesz nad progami i scenariuszami; nie chcesz, by długie uruchomienia testów stresu blokowały edytor, więc trzymaj uruchomienia w edytorze na poziomie 30-sekundowego smoke testu.

Praktyczny podział jest warstwowy: 30-sekundowy smoke test na każdym PR, pełny test obciążenia w nocy, test stresu co tydzień. Smoke test łapie oczywiste regresje; dłuższe przebiegi łapią subtelne, nie wstrzymując merge’a.

Liczby z testów obciążenia kłamią w przewidywalny sposób. Oto tryby awarii, które wysyłają zespoły w pogoń za niewłaściwą naprawą.

Gdy wynik wygląda na niemożliwy, przekaż swojemu narzędziu AI pełne podsumowanie k6 i metryki zasobów generatora i poproś, żeby odróżniło prawdziwe wąskie gardło serwera od artefaktu testu, zanim eskalujesz.