1. Giới thiệu k6
k6 (Grafana k6) là open-source load testing tool viết bằng Go, sử dụng JavaScript/TypeScript cho test scripts. Ưu điểm: nhẹ, nhanh, developer-friendly, tích hợp tốt với Grafana ecosystem.
# Cài đặt
brew install k6 # macOS
sudo apt install k6 # Ubuntu/Debian
docker run --rm -i grafana/k6 run # Docker
# Chạy test
k6 run script.js
k6 run --vus 50 --duration 5m script.js
2. k6 Scripting Cơ bản
// tests/load/basic.js
import http from 'k6/http';
import { check, group, sleep } from 'k6';
import { Rate, Trend } from 'k6/metrics';
// Custom metrics
const errorRate = new Rate('errors');
const productLatency = new Trend('product_latency');
export const options = {
stages: [
{ duration: '2m', target: 50 }, // Ramp up
{ duration: '5m', target: 50 }, // Steady state
{ duration: '2m', target: 100 }, // Scale up
{ duration: '5m', target: 100 }, // Steady state
{ duration: '2m', target: 0 }, // Ramp down
],
thresholds: {
http_req_duration: ['p(95)<300', 'p(99)<1000'],
http_req_failed: ['rate<0.01'],
errors: ['rate<0.05'],
product_latency: ['p(95)<200'],
},
};
const BASE_URL = __ENV.BASE_URL || 'http://localhost:3000';
export default function () {
group('Browse Products', () => {
const listRes = http.get(`${BASE_URL}/api/products?page=1&limit=20`);
check(listRes, {
'list status 200': (r) => r.status === 200,
'has products': (r) => JSON.parse(r.body).data.length > 0,
});
errorRate.add(listRes.status !== 200);
// Get product detail
const products = JSON.parse(listRes.body).data;
if (products.length > 0) {
const id = products[Math.floor(Math.random() * products.length)].id;
const detailRes = http.get(`${BASE_URL}/api/products/${id}`);
productLatency.add(detailRes.timings.duration);
check(detailRes, {
'detail status 200': (r) => r.status === 200,
});
}
});
sleep(Math.random() * 3 + 1); // Think time: 1-4s
}
3. Scenarios — Mô hình tải nâng cao
export const options = {
scenarios: {
// Scenario 1: Shared iterations (fixed total)
smoke: {
executor: 'shared-iterations',
vus: 5,
iterations: 100,
maxDuration: '2m',
},
// Scenario 2: Constant arrival rate (fixed RPS)
constant_load: {
executor: 'constant-arrival-rate',
rate: 100, // 100 RPS
timeUnit: '1s',
duration: '10m',
preAllocatedVUs: 50,
maxVUs: 200,
startTime: '2m', // Bắt đầu sau 2 phút
},
// Scenario 3: Ramping arrival rate (thay đổi RPS)
ramping_load: {
executor: 'ramping-arrival-rate',
startRate: 10,
timeUnit: '1s',
stages: [
{ duration: '5m', target: 200 }, // Ramp to 200 RPS
{ duration: '10m', target: 200 }, // Sustain
{ duration: '5m', target: 500 }, // Scale up
{ duration: '10m', target: 500 }, // Sustain peak
{ duration: '5m', target: 0 }, // Ramp down
],
preAllocatedVUs: 100,
maxVUs: 500,
startTime: '12m',
},
// Scenario 4: Spike test
spike: {
executor: 'ramping-vus',
stages: [
{ duration: '10s', target: 1000 }, // Spike!
{ duration: '1m', target: 1000 }, // Sustain
{ duration: '10s', target: 0 }, // Drop
],
startTime: '35m',
},
},
};
4. Data-driven Testing
import { SharedArray } from 'k6/data';
import papaparse from 'https://jslib.k6.io/papaparse/5.1.1/index.js';
// Load CSV data (shared across VUs — memory efficient)
const users = new SharedArray('users', function () {
return papaparse.parse(open('./data/users.csv'), { header: true }).data;
});
const products = new SharedArray('products', function () {
return JSON.parse(open('./data/products.json'));
});
export default function () {
// Random user credentials
const user = users[Math.floor(Math.random() * users.length)];
// Login
const loginRes = http.post(`${BASE_URL}/api/auth/login`, JSON.stringify({
email: user.email,
password: user.password,
}), { headers: { 'Content-Type': 'application/json' } });
const token = JSON.parse(loginRes.body).accessToken;
const authHeaders = {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
};
// Browse with auth
const product = products[Math.floor(Math.random() * products.length)];
http.get(`${BASE_URL}/api/products/${product.id}`, authHeaders);
sleep(2);
}
5. Output Integrations
# Output to Prometheus (remote write)
k6 run --out experimental-prometheus-rw script.js
# Output to InfluxDB
k6 run --out influxdb=http://localhost:8086/k6 script.js
# Output to JSON (for CI analysis)
k6 run --out json=results.json script.js
# Output to Grafana Cloud k6
K6_CLOUD_TOKEN=xxx k6 cloud script.js
# Multiple outputs
k6 run --out json=results.json --out experimental-prometheus-rw script.js
6. k6 Browser Module
// Hybrid: protocol + browser testing
import { browser } from 'k6/browser';
import { check } from 'k6';
export const options = {
scenarios: {
browser_test: {
executor: 'constant-vus',
vus: 5,
duration: '5m',
options: { browser: { type: 'chromium' } },
},
},
thresholds: {
browser_web_vital_lcp: ['p(95)<2500'],
browser_web_vital_fid: ['p(95)<100'],
browser_web_vital_cls: ['p(95)<0.1'],
},
};
export default async function () {
const page = await browser.newPage();
try {
await page.goto('https://example.com');
// Measure Core Web Vitals
await page.waitForSelector('.product-list');
check(page, {
'page loaded': (p) => p.locator('h1').textContent() !== '',
});
// User interaction
await page.locator('.search-input').fill('laptop');
await page.locator('.search-btn').click();
await page.waitForSelector('.search-results');
} finally {
await page.close();
}
}
7. k6 Operator cho Kubernetes
# k6-test.yaml - Distributed load test trên K8s
apiVersion: k6.io/v1alpha1
kind: TestRun
metadata:
name: load-test-products
spec:
parallelism: 10 # 10 pods chạy song song
script:
configMap:
name: k6-test-scripts
file: load-test.js
arguments: --out experimental-prometheus-rw
runner:
resources:
limits:
cpu: "500m"
memory: "256Mi"
# Deploy k6 operator
helm install k6-operator grafana/k6-operator
# Run distributed test
kubectl apply -f k6-test.yaml
kubectl get testrun -w # Watch progress
8. Tổng kết
- k6: JavaScript-based, Go runtime, developer-friendly
- Scenarios: shared-iterations, constant-arrival-rate, ramping-arrival-rate
- Thresholds: Auto pass/fail dựa trên SLO targets
- Browser module: Front-end performance + Core Web Vitals
- k6 Operator: Distributed testing trên Kubernetes
- Integrations: Prometheus, Grafana, InfluxDB, Cloud
Bài tiếp theo sẽ so sánh Gatling và Artillery.