1. REST API Performance Testing
// k6 — REST API load test với correlation
import http from 'k6/http';
import { check, group } from 'k6';
export const options = {
scenarios: {
rest_api: {
executor: 'constant-arrival-rate',
rate: 200, // 200 RPS
timeUnit: '1s',
duration: '10m',
preAllocatedVUs: 100,
},
},
thresholds: {
'http_req_duration{name:ListProducts}': ['p(95)<150'],
'http_req_duration{name:GetProduct}': ['p(95)<100'],
'http_req_duration{name:CreateOrder}': ['p(95)<500'],
},
};
export default function () {
group('REST API Flow', () => {
// 1. List products (paginated)
const listRes = http.get(`${BASE_URL}/api/products?page=1&limit=20`, {
tags: { name: 'ListProducts' },
});
check(listRes, { 'list 200': (r) => r.status === 200 });
// 2. Correlation: lấy ID từ response trước
const products = JSON.parse(listRes.body).data;
const productId = products[0]?.id;
if (productId) {
const detailRes = http.get(`${BASE_URL}/api/products/${productId}`, {
tags: { name: 'GetProduct' },
});
check(detailRes, { 'detail 200': (r) => r.status === 200 });
}
// 3. POST with JSON body
const orderRes = http.post(`${BASE_URL}/api/orders`, JSON.stringify({
productId,
quantity: 1,
}), {
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
tags: { name: 'CreateOrder' },
});
check(orderRes, { 'order 201': (r) => r.status === 201 });
});
}
2. GraphQL Performance Testing
// k6 — GraphQL load test
import http from 'k6/http';
import { check } from 'k6';
const GRAPHQL_URL = `${__ENV.BASE_URL}/graphql`;
// Query đơn giản
function listProducts() {
const query = `
query ListProducts($limit: Int!, $offset: Int!) {
products(limit: $limit, offset: $offset) {
id
name
price
category { name }
}
}
`;
return http.post(GRAPHQL_URL, JSON.stringify({
query,
variables: { limit: 20, offset: 0 },
}), {
headers: { 'Content-Type': 'application/json' },
tags: { name: 'GQL_ListProducts' },
});
}
// Query phức tạp — test N+1 performance
function deepNestedQuery() {
const query = `
query DeepQuery {
users(limit: 50) {
id
name
orders(limit: 10) {
id
total
items {
product {
name
reviews(limit: 5) {
rating
author { name }
}
}
}
}
}
}
`;
return http.post(GRAPHQL_URL, JSON.stringify({ query }), {
headers: { 'Content-Type': 'application/json' },
tags: { name: 'GQL_DeepNested' },
});
}
export default function () {
// Test query complexity impact
const simpleRes = listProducts();
check(simpleRes, {
'simple query < 200ms': (r) => r.timings.duration < 200,
'no errors': (r) => !JSON.parse(r.body).errors,
});
const deepRes = deepNestedQuery();
check(deepRes, {
'deep query < 2000ms': (r) => r.timings.duration < 2000,
});
}
3. gRPC Performance Testing
// k6 — gRPC load test (k6 có built-in gRPC support)
import grpc from 'k6/net/grpc';
import { check } from 'k6';
const client = new grpc.Client();
client.load(['proto'], 'product.proto');
export const options = {
scenarios: {
grpc_test: {
executor: 'constant-arrival-rate',
rate: 500,
timeUnit: '1s',
duration: '5m',
preAllocatedVUs: 100,
},
},
thresholds: {
grpc_req_duration: ['p(95)<100', 'p(99)<300'],
},
};
export default function () {
client.connect('localhost:50051', { plaintext: true });
// Unary RPC
const response = client.invoke('product.ProductService/GetProduct', {
id: 'prod-001',
});
check(response, {
'status OK': (r) => r.status === grpc.StatusOK,
'has product': (r) => r.message.name !== '',
});
// Server streaming
const stream = client.invoke('product.ProductService/ListProducts', {
category: 'electronics',
limit: 100,
});
check(stream, {
'stream OK': (r) => r.status === grpc.StatusOK,
});
client.close();
}
4. WebSocket Performance Testing
// k6 — WebSocket connection scaling
import ws from 'k6/ws';
import { check } from 'k6';
import { Counter, Trend } from 'k6/metrics';
const wsMessages = new Counter('ws_messages_received');
const wsLatency = new Trend('ws_message_latency');
export const options = {
stages: [
{ duration: '2m', target: 100 }, // 100 concurrent WebSocket connections
{ duration: '5m', target: 500 }, // Scale to 500
{ duration: '5m', target: 1000 }, // Scale to 1000
{ duration: '2m', target: 0 },
],
};
export default function () {
const url = 'wss://api.example.com/ws/chat';
const res = ws.connect(url, {
headers: { 'Authorization': `Bearer ${token}` },
}, function (socket) {
socket.on('open', () => {
// Join room
socket.send(JSON.stringify({
event: 'joinRoom',
data: { room: 'general' },
}));
// Send messages periodically
socket.setInterval(() => {
const sendTime = Date.now();
socket.send(JSON.stringify({
event: 'sendMessage',
data: { room: 'general', message: `Msg-${sendTime}`, ts: sendTime },
}));
}, 2000);
});
socket.on('message', (msg) => {
wsMessages.add(1);
const data = JSON.parse(msg);
if (data.ts) {
wsLatency.add(Date.now() - data.ts);
}
});
socket.setTimeout(() => socket.close(), 60000); // Close after 60s
});
check(res, {
'WS connected': (r) => r && r.status === 101,
});
}
5. Event-driven Systems Testing
// k6 xk6-kafka — Kafka producer/consumer throughput
import { Writer, Reader, Connection } from 'k6/x/kafka';
const writer = new Writer({
brokers: ['kafka:9092'],
topic: 'orders',
});
const reader = new Reader({
brokers: ['kafka:9092'],
topic: 'order-events',
groupID: 'load-test-consumer',
});
export default function () {
// Produce messages
const messages = Array.from({ length: 100 }, (_, i) => ({
key: `order-${Date.now()}-${i}`,
value: JSON.stringify({
orderId: `ORD-${Date.now()}`,
amount: Math.random() * 1000,
timestamp: new Date().toISOString(),
}),
}));
writer.produce({ messages });
// Consume and measure lag
const consumed = reader.consume({ limit: 100 });
// Measure consumer lag, processing time, throughput
}
export function teardown() {
writer.close();
reader.close();
}
6. Summary
- REST: Correlation, parameterization, per-endpoint thresholds
- GraphQL: Test query complexity impact, N+1 detection, batch queries
- gRPC: Built-in k6 support, streaming performance, serialization overhead
- WebSocket: Connection scaling, message latency, reconnection handling
- Event-driven: Producer/consumer throughput, consumer lag, scaling partition
The next article will explore Database Performance Testing.