用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/thiagofernandes1987-create/APEX --skill k6-load-testing命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
| name | k6-load-testing |
| description | "Use when you need to load test HTTP APIs, WebSocket endpoints, or browser scenarios" |
k6 is a modern, developer-centric load testing tool that helps you write and execute performance tests for HTTP APIs, WebSocket endpoints, and browser scenarios. This skill provides comprehensive guidance on writing realistic load tests, configuring test scenarios (smoke, load, stress, spike, soak), analyzing results, and integrating with CI/CD pipelines.
Use this skill when you need to validate system performance, identify bottlenecks, ensure SLA compliance, or catch performance regressions before deployment.
# macOS
brew install k6
# Windows
choco install k6
# Linux
sudo gpg -k
sudo gpg --no-default-keyring --keyring /usr/share/keyrings/k6-archive-keyring.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69
echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list
sudo apt-get update
sudo apt-get install k6
// simple-test.js
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
vus: 10,
duration: '30s',
};
export default function () {
const res = http.get('https://httpbin.test.k6.io/get');
check(res, {
'status is 200': (r) => r.status === 200,
'response time < 500ms': (r) => r.timings.duration < 500,
});
sleep(1);
}
Run with: k6 run simple-test.js
export const options = {
// Virtual Users (concurrent users)
vus: 100,
// Test duration
duration: '5m',
// Or use stages for ramp-up/ramp-down
stages: [
{ duration: '30s', target: 20 }, // Ramp up
{ duration: '1m', target: 100 }, // Stay at 100
{ duration: '30s', target: 0 }, // Ramp down
],
// Thresholds (SLA)
thresholds: {
http_req_duration: ['p(95)<500'], // 95% requests < 500ms
http_req_failed: ['rate<0.01'], // Error rate < 1%
},
// Load zones (distributed testing)
ext: {
loadimpact: {
name: 'My Load Test',
distribution: {
'amazon:us:ashburn': { weight: 50 },
'amazon:eu: Dublin': { weight: 50 },
},
},
},
};
| Type | Use Case | Configuration |
|---|---|---|
| Smoke Test | Verify basic functionality | Low VUs (1-5), short duration |
| Load Test | Normal expected load | Target VUs based on traffic |
| Stress Test | Find breaking point | Ramp beyond capacity |
| Spike Test | Sudden traffic spikes | Rapid increase/decrease |
| Soak Test | Long-term stability | Extended duration |
import http from 'k6/http';
import { check, sleep } from 'k6';
export default function () {
// GET request
const getRes = http.get('https://api.example.com/users');
check(getRes, {
'GET succeeded': (r) => r.status === 200,
'has users': (r) => r.json('data.length') > 0,
});
// POST request with JSON body
const postRes = http.post('https://api.example.com/users',
JSON.stringify({ name: 'Test User', email: 'test@example.com' }),
{
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + __ENV.API_TOKEN,
},
}
);
check(postRes, {
'POST succeeded': (r) => r.status === 201,
'user created': (r) => r.() !== ,
});
();
}
import http from 'k6/http';
import { check } from 'k6';
export default function () {
// Login and extract token
const loginRes = http.post('https://api.example.com/login',
JSON.stringify({ email: 'test@example.com', password: 'password123' })
);
const token = loginRes.json('access_token');
// Use token in subsequent requests
const headers = {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
};
const profileRes = http.get('https://api.example.com/profile', {
headers: headers,
});
check(profileRes, {
'profile loaded': (r) => r.status === 200,
});
}
import http from 'k6/http';
import { check } from 'k6';
const usernames = ['user1', 'user2', 'user3', 'user4', 'user5'];
export default function () {
// Use shared array with VU-specific index
const username = usernames[__VU % usernames.length];
const res = http.get(`https://api.example.com/users/${username}`);
check(res, {
'user found': (r) => r.status === 200,
});
}
import { browser } from 'k6/browser';
export const options = {
scenarios: {
browser_test: {
executor: 'constant-vus',
vus: 5,
duration: '30s',
browser: {
type: 'chromium',
},
},
},
};
export default async function () {
const page = await browser.newPage();
try {
await page.goto('https://example.com');
const title = await page.title();
console.log(`Page title: ${title}`);
// Click and interact
await page.click('button[data-testid="submit"]');
// Wait for response
await page.waitForSelector('.success-message');
} finally {
await page.close();
}
}
Install browser support: k6 install chromium
import ws from 'k6/ws';
import { check } from 'k6';
export default function () {
const url = 'wss://echo.websocket.org';
ws.connect(url, {}, function (socket) {
socket.on('open', () => {
console.log('WebSocket connected');
socket.send('Hello WebSocket');
});
socket.on('message', (data) => {
console.log(`Received: ${data}`);
check(data, {
'echo received': (d) => d.includes('Hello'),
});
});
socket.on('close', () => {
console.log('WebSocket closed');
});
// Send periodic messages
socket.setInterval(function () {
socket.send('ping');
}, 1000);
socket.( () {
socket.();
}, );
});
}
import http from 'k6/http';
import { check } from 'k6';
import { SharedArray } from 'k6/data';
// Option 1: Load once, shared across VUs
const users = new SharedArray('users', function () {
return open('./users.csv').split('\n').slice(1).map(line => {
const [email, password] = line.split(',');
return { email, password };
});
});
export default function () {
const user = users[__VU % users.length];
const res = http.post('https://api.example.com/login',
JSON.stringify({ email: user.email, password: user.password })
);
check(res, { 'login successful': (r) => r.status === 200 });
}
import http from 'k6/http';
import { check } from 'k6';
import { SharedArray } from 'k6/data';
const products = new SharedArray('products', function () {
return JSON.parse(open('./products.json'));
});
export default function () {
const product = products[Math.floor(Math.random() * products.length)];
const res = http.get(`https://api.example.com/products/${product.id}`);
check(res, { 'product found': (r) => r.status === 200 });
}
export const options = {
vus: 50,
duration: '2m',
thresholds: {
// Response time thresholds
http_req_duration: ['p(95)<500', 'p(99)<1000'],
// Error rate threshold
http_req_failed: ['rate<0.01'],
// Throughput threshold
http_reqs: ['rate>100'],
},
};
export const options = {
thresholds: {
// Multiple thresholds on same metric
http_req_duration: [
'p(90)<300', // 90th percentile < 300ms
'p(95)<500', // 95th percentile < 500ms
'p(99)<1000', // 99th percentile < 1s
'avg<200', // average < 200ms
],
// Custom metrics
my_custom_metric: ['avg<100'],
// Abort on threshold failure
'http_req_duration{method:GET}': ['p(95)<300'],
},
};
import http from 'k6/http';
import { Counter, Trend, Rate, Gauge } from 'k6/metrics';
// Define custom metrics
const myCounter = new Counter('api_calls_total');
const responseTime = new Trend('response_time');
const errorRate = new Rate('error_rate');
const activeUsers = new Gauge('active_users');
export default function () {
const res = http.get('https://api.example.com/data');
// Increment counter
myCounter.add(1);
// Add to trend (for percentiles)
responseTime.add(res.timings.duration);
// Track error rate
errorRate.add(res.status !== 200);
// Set gauge value
activeUsers.add(__VU);
// Tagged metrics
const taggedRes = http.get(, {
: { : , : },
});
}
# .github/workflows/load-test.yml
name: Load Tests
on:
push:
branches: [main]
schedule:
- cron: '0 2 * * *' # Daily at 2 AM
jobs:
load-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup k6
uses: grafana/k6-action@v0.2.0
- name: Run load test
env:
API_TOKEN: ${{ secrets.API_TOKEN }}
run: k6 run --out json=results.json load-test.js
- name: Upload results
uses: actions/upload-artifact@v4
with:
name: k6-results
path: results.json
-
# .gitlab-ci.yml
load_test:
image: grafana/k6:latest
script:
- k6 run load-test.js
artifacts:
when: always
paths:
- results.json
reports:
junit: results.xml
# Text summary
k6 run load-test.js
# JSON output for parsing
k6 run --out json=results.json load-test.js
# InfluxDB + Grafana
k6 run --out influxdb=http://localhost:8086/k6 load-test.js
# Prometheus remote write
k6 run --out prometheus=localhost:9090/k6 load-test.js
# Cloud results
k6 run --out cloud load-test.js
| Metric | Description | Good | Warning | Bad |
|---|---|---|---|---|
| http_req_duration (p95) | 95% response time | < 300ms | 300-500ms | > 500ms |
| http_req_failed | Error rate | < 0.1% | 0.1-1% | > 1% |
| http_reqs | Requests/sec | Meeting target | Near limit | At limit |
| vus | Virtual users | Stable | Gradual increase | Unexpected spike |
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
vus: 50,
duration: '2m',
thresholds: {
http_req_duration: ['p(95)<500'],
http_req_failed: ['rate<0.01'],
},
};
export default function () {
const res = http.get('https://api.example.com/users');
check(res, {
'status is 200': (r) => r.status === 200,
'response time < 500ms': (r) => r.timings.duration < 500,
});
sleep(1);
}
import http from 'k6/http';
import { check } from 'k6';
import { SharedArray } from 'k6/data';
const users = new SharedArray('users', function () {
return JSON.parse(open('./users.json'));
});
export default function () {
const user = users[__VU % users.length];
const loginRes = http.post('https://api.example.com/login',
JSON.stringify({ email: user.email, password: user.password })
);
const token = loginRes.json('access_token');
const headers = { 'Authorization': `Bearer ${token}` };
const res = http.get('https://api.example.com/profile', { headers });
check(res, { 'profile loaded': (r) => r.status === 200 });
}
tags: { endpoint: 'users' })Problem: Tests pass locally but fail in CI Solution: Ensure CI environment has similar resources and network conditions
Problem: Inconsistent results between runs Solution: Check for external dependencies, random data, or test data pollution
Problem: k6 runs out of memory
Solution: Use SharedArray for large data, reduce VUs, or use --max-memory flag
Problem: Thresholds too strict Solution: Start with relaxed thresholds, tighten based on historical data
@performance-engineer - For broader performance optimization@api-testing-observability-api-mock - For API mocking during testing@application-performance-performance-optimization - For performance optimizationImplement —
基于 SOC 职业分类