Why Load Testing?
Load testing reveals how your system behaves under stress. It's essential for capacity planning, finding bottlenecks, and preventing production incidents.
Types of Load Tests
Load Test
Simulate expected peak load:
// k6 load test
export const options = {
stages: [
{ duration: '2m', target: 100 }, // Ramp up
{ duration: '5m', target: 100 }, // Stay at peak
{ duration: '2m', target: 0 }, // Ramp down
],
};Stress Test
Find the breaking point:
export const options = {
stages: [
{ duration: '2m', target: 100 },
{ duration: '5m', target: 100 },
{ duration: '2m', target: 200 },
{ duration: '5m', target: 200 },
{ duration: '2m', target: 300 }, // Keep increasing
{ duration: '5m', target: 300 },
],
};Spike Test
Simulate sudden traffic surge:
export const options = {
stages: [
{ duration: '10s', target: 100 },
{ duration: '1m', target: 100 },
{ duration: '10s', target: 1000 }, // Spike!
{ duration: '3m', target: 1000 },
{ duration: '10s', target: 100 },
],
};Soak Test
Test for memory leaks and degradation:
export const options = {
stages: [
{ duration: '5m', target: 100 },
{ duration: '8h', target: 100 }, // Run for hours
{ duration: '5m', target: 0 },
],
};Writing Realistic Tests
k6 Test Script
import http from 'k6/http';
import { check, sleep } from 'k6';
export default function() {
// Simulate user journey
const homeRes = http.get('https://api.example.com/');
check(homeRes, {
'home status 200': (r) => r.status === 200,
'home response time < 500ms': (r) => r.timings.duration < 500,
});
sleep(1); // Think time
const loginRes = http.post('https://api.example.com/login', {
email: 'test@example.com',
password: 'password',
});
check(loginRes, {
'login successful': (r) => r.status === 200,
});
const token = loginRes.json('token');
// Authenticated request
const profileRes = http.get('https://api.example.com/profile', {
headers: { Authorization: `Bearer ${token}` },
});
sleep(Math.random() * 3); // Variable think time
}Key Metrics
What to Measure
- Response Time: p50, p95, p99
- Throughput: Requests per second
- Error Rate: Failed requests percentage
- Concurrent Users: Active virtual users
Thresholds
export const options = {
thresholds: {
http_req_duration: ['p(95)<500'], // 95% under 500ms
http_req_failed: ['rate<0.01'], // Less than 1% errors
http_reqs: ['rate>100'], // At least 100 RPS
},
};CI/CD Integration
# GitHub Actions
jobs:
load-test:
runs-on: ubuntu-latest
steps:
- uses: grafana/k6-action@v0.3.0
with:
filename: load-tests/api-test.js
flags: --out cloudAnalyzing Results
- Compare against baseline
- Identify bottlenecks (CPU, memory, database)
- Correlate with application metrics
- Document findings and recommendations
Conclusion
Load testing should be part of your regular development cycle. Test early, test often, and always test before major releases.