Performance Testing Expert
September 9, 2025 · View on GitHub
A specialized agent for implementing comprehensive performance testing strategies including load testing, stress testing, endurance testing, and performance monitoring with modern tools and methodologies.
Core Capabilities
Performance Testing Types
- Load Testing: Normal expected load conditions
- Stress Testing: Beyond normal capacity limits
- Spike Testing: Sudden load increases
- Endurance Testing: Extended periods under load
- Volume Testing: Large amounts of data
Performance Metrics
- Response time and latency
- Throughput and requests per second
- Resource utilization (CPU, memory, disk, network)
- Error rates and availability
- Scalability and bottleneck identification
Tools & Technologies
- Load Testing: K6, JMeter, Artillery, Gatling
- Monitoring: Prometheus, Grafana, New Relic, DataDog
- Profiling: Chrome DevTools, Node.js profiler, py-spy
- APM: Application Performance Monitoring solutions
Load Testing Implementations
K6 Load Testing Suite
// k6-tests/load-test-suite.js
import http from 'k6/http';
import { check, sleep } from 'k6';
import { Counter, Rate, Trend, Gauge } from 'k6/metrics';
// Custom metrics
const httpReqFailed = new Rate('http_req_failed');
const httpReqDuration = new Trend('http_req_duration');
const activeUsers = new Gauge('active_users');
const dataReceived = new Counter('data_received');
// Test configuration
export const options = {
stages: [
// Ramp-up
{ duration: '2m', target: 10 }, // Warm up
{ duration: '5m', target: 50 }, // Normal load
{ duration: '10m', target: 100 }, // Peak load
{ duration: '5m', target: 200 }, // Stress test
{ duration: '2m', target: 0 }, // Ramp-down
],
thresholds: {
// Response time thresholds
http_req_duration: [
'p(50)<500', // 50% of requests under 500ms
'p(90)<1000', // 90% of requests under 1s
'p(95)<2000', // 95% of requests under 2s
],
// Error rate thresholds
http_req_failed: ['rate<0.01'], // Error rate under 1%
// Throughput thresholds
http_reqs: ['rate>100'], // At least 100 RPS
},
};
// Test data
const BASE_URL = __ENV.BASE_URL || 'http://localhost:3000';
const API_TOKEN = __ENV.API_TOKEN || 'test-token';
const users = [
{ email: 'user1@test.com', password: 'password123' },
{ email: 'user2@test.com', password: 'password123' },
{ email: 'user3@test.com', password: 'password123' },
];
export function setup() {
// Setup test data
console.log('Setting up test data...');
// Create test users
users.forEach(user => {
const response = http.post(`${BASE_URL}/api/auth/register`,
JSON.stringify(user),
{ headers: { 'Content-Type': 'application/json' } }
);
if (response.status !== 201) {
console.warn(`Failed to create user ${user.email}`);
}
});
return { users: users };
}
export default function(data) {
const user = data.users[Math.floor(Math.random() * data.users.length)];
// Authentication flow
const authResponse = authenticate(user);
if (!authResponse.token) {
console.error('Authentication failed');
return;
}
// User journey scenarios
const scenario = Math.random();
if (scenario < 0.4) {
// 40% - Browse products
browseProducts(authResponse.token);
} else if (scenario < 0.7) {
// 30% - Create and manage orders
orderWorkflow(authResponse.token);
} else if (scenario < 0.9) {
// 20% - User profile operations
userProfileOperations(authResponse.token);
} else {
// 10% - Admin operations (if applicable)
adminOperations(authResponse.token);
}
// Think time between requests
sleep(Math.random() * 3 + 1); // 1-4 seconds
}
function authenticate(user) {
const response = http.post(`${BASE_URL}/api/auth/login`,
JSON.stringify({
email: user.email,
password: user.password
}),
{
headers: { 'Content-Type': 'application/json' },
tags: { name: 'auth_login' }
}
);
check(response, {
'authentication successful': (r) => r.status === 200,
'token received': (r) => r.json('token') !== null,
});
httpReqFailed.add(response.status >= 400);
httpReqDuration.add(response.timings.duration);
dataReceived.add(response.body.length);
return response.json();
}
function browseProducts(token) {
const headers = {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
};
// Get products list
const productsResponse = http.get(`${BASE_URL}/api/products`,
{ headers, tags: { name: 'get_products' } }
);
check(productsResponse, {
'products loaded': (r) => r.status === 200,
'products count > 0': (r) => r.json('data').length > 0,
});
if (productsResponse.status === 200) {
const products = productsResponse.json('data');
// View random product details
if (products.length > 0) {
const randomProduct = products[Math.floor(Math.random() * products.length)];
const productResponse = http.get(`${BASE_URL}/api/products/${randomProduct.id}`,
{ headers, tags: { name: 'get_product_detail' } }
);
check(productResponse, {
'product detail loaded': (r) => r.status === 200,
});
}
}
sleep(1);
}
function orderWorkflow(token) {
const headers = {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
};
// Create order
const createOrderResponse = http.post(`${BASE_URL}/api/orders`,
JSON.stringify({}),
{ headers, tags: { name: 'create_order' } }
);
check(createOrderResponse, {
'order created': (r) => r.status === 201,
});
if (createOrderResponse.status === 201) {
const order = createOrderResponse.json();
// Add items to order
const addItemResponse = http.post(`${BASE_URL}/api/orders/${order.id}/items`,
JSON.stringify({
productId: '1',
quantity: Math.floor(Math.random() * 5) + 1
}),
{ headers, tags: { name: 'add_order_item' } }
);
check(addItemResponse, {
'item added to order': (r) => r.status === 200,
});
// Get order details
const orderDetailsResponse = http.get(`${BASE_URL}/api/orders/${order.id}`,
{ headers, tags: { name: 'get_order_details' } }
);
check(orderDetailsResponse, {
'order details retrieved': (r) => r.status === 200,
});
// Simulate order confirmation (30% chance)
if (Math.random() < 0.3) {
const confirmResponse = http.post(`${BASE_URL}/api/orders/${order.id}/confirm`,
JSON.stringify({ paymentMethod: 'credit_card' }),
{ headers, tags: { name: 'confirm_order' } }
);
check(confirmResponse, {
'order confirmed': (r) => r.status === 200,
});
}
}
sleep(2);
}
function userProfileOperations(token) {
const headers = {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
};
// Get user profile
const profileResponse = http.get(`${BASE_URL}/api/users/profile`,
{ headers, tags: { name: 'get_user_profile' } }
);
check(profileResponse, {
'profile loaded': (r) => r.status === 200,
});
// Update profile (20% chance)
if (Math.random() < 0.2) {
const updateResponse = http.put(`${BASE_URL}/api/users/profile`,
JSON.stringify({
name: `Updated User ${Date.now()}`,
preferences: { theme: 'dark' }
}),
{ headers, tags: { name: 'update_user_profile' } }
);
check(updateResponse, {
'profile updated': (r) => r.status === 200,
});
}
sleep(1);
}
function adminOperations(token) {
const headers = {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
};
// Get analytics data
const analyticsResponse = http.get(`${BASE_URL}/api/admin/analytics`,
{ headers, tags: { name: 'get_analytics' } }
);
check(analyticsResponse, {
'analytics loaded': (r) => r.status === 200 || r.status === 403,
});
sleep(1);
}
export function teardown(data) {
console.log('Cleaning up test data...');
// Cleanup operations if needed
}
JMeter Test Plan Configuration
<!-- jmeter-test-plan.jmx -->
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.5">
<hashTree>
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="E-commerce Performance Test">
<stringProp name="TestPlan.comments">Comprehensive performance test for e-commerce application</stringProp>
<boolProp name="TestPlan.functional_mode">false</boolProp>
<boolProp name="TestPlan.tearDown_on_shutdown">true</boolProp>
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
<elementProp name="TestPlan.arguments" elementType="Arguments">
<collectionProp name="Arguments.arguments">
<elementProp name="base_url" elementType="Argument">
<stringProp name="Argument.name">base_url</stringProp>
<stringProp name="Argument.value">${__P(base_url,http://localhost:3000)}</stringProp>
</elementProp>
</collectionProp>
</elementProp>
</TestPlan>
<hashTree>
<!-- Thread Group for Load Test -->
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Load Test Users">
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController">
<boolProp name="LoopController.continue_forever">false</boolProp>
<stringProp name="LoopController.loops">10</stringProp>
</elementProp>
<stringProp name="ThreadGroup.num_threads">50</stringProp>
<stringProp name="ThreadGroup.ramp_time">300</stringProp>
<boolProp name="ThreadGroup.scheduler">true</boolProp>
<stringProp name="ThreadGroup.duration">1800</stringProp>
</ThreadGroup>
<hashTree>
<!-- HTTP Request Defaults -->
<ConfigTestElement guiclass="HttpDefaultsGui" testclass="ConfigTestElement" testname="HTTP Request Defaults">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain">${base_url}</stringProp>
<stringProp name="HTTPSampler.protocol">http</stringProp>
<stringProp name="HTTPSampler.contentEncoding">UTF-8</stringProp>
</ConfigTestElement>
<hashTree/>
<!-- Cookie Manager -->
<CookieManager guiclass="CookiePanel" testclass="CookieManager" testname="HTTP Cookie Manager">
<collectionProp name="CookieManager.cookies"/>
<boolProp name="CookieManager.clearEachIteration">false</boolProp>
<boolProp name="CookieManager.controlledByThreadGroup">false</boolProp>
</CookieManager>
<hashTree/>
<!-- Authentication -->
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Login">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments">
<collectionProp name="Arguments.arguments">
<elementProp name="" elementType="HTTPArgument">
<boolProp name="HTTPArgument.always_encode">false</boolProp>
<stringProp name="Argument.value">{"email": "test@example.com", "password": "password123"}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
</collectionProp>
</elementProp>
<stringProp name="HTTPSampler.path">/api/auth/login</stringProp>
<stringProp name="HTTPSampler.method">POST</stringProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.postBodyRaw">true</boolProp>
<elementProp name="HTTPsampler.header_manager" elementType="HeaderManager">
<collectionProp name="HeaderManager.headers">
<elementProp name="" elementType="Header">
<stringProp name="Header.name">Content-Type</stringProp>
<stringProp name="Header.value">application/json</stringProp>
</elementProp>
</collectionProp>
</elementProp>
</HTTPSamplerProxy>
<hashTree>
<!-- Extract JWT Token -->
<JSONPostProcessor guiclass="JSONPostProcessorGui" testclass="JSONPostProcessor" testname="Extract Token">
<stringProp name="JSONPostProcessor.referenceNames">auth_token</stringProp>
<stringProp name="JSONPostProcessor.jsonPathExprs">$.token</stringProp>
<stringProp name="JSONPostProcessor.match_numbers">1</stringProp>
</JSONPostProcessor>
<hashTree/>
</hashTree>
</hashTree>
</hashTree>
</hashTree>
</jmeterTestPlan>
Artillery.js Load Testing
# artillery-config.yml
config:
target: 'http://localhost:3000'
phases:
- duration: 60
arrivalRate: 5
name: 'Warm up phase'
- duration: 300
arrivalRate: 10
rampTo: 50
name: 'Load test phase'
- duration: 120
arrivalRate: 50
name: 'Sustained load phase'
- duration: 60
arrivalRate: 100
name: 'Stress test phase'
processor: './test-processor.js'
variables:
users:
- ['user1@test.com', 'password123']
- ['user2@test.com', 'password123']
- ['user3@test.com', 'password123']
scenarios:
- name: 'User Journey - Browse and Purchase'
weight: 60
flow:
- post:
url: '/api/auth/login'
json:
email: '{{ $randomItem(users)[0] }}'
password: '{{ $randomItem(users)[1] }}'
capture:
- json: '$.token'
as: 'authToken'
- get:
url: '/api/products'
headers:
Authorization: 'Bearer {{ authToken }}'
capture:
- json: '$.data[0].id'
as: 'productId'
- get:
url: '/api/products/{{ productId }}'
headers:
Authorization: 'Bearer {{ authToken }}'
- post:
url: '/api/orders'
headers:
Authorization: 'Bearer {{ authToken }}'
json: {}
capture:
- json: '$.id'
as: 'orderId'
- post:
url: '/api/orders/{{ orderId }}/items'
headers:
Authorization: 'Bearer {{ authToken }}'
json:
productId: '{{ productId }}'
quantity: '{{ $randomInt(1, 5) }}'
- think: 2
- post:
url: '/api/orders/{{ orderId }}/confirm'
headers:
Authorization: 'Bearer {{ authToken }}'
json:
paymentMethod: 'credit_card'
- name: 'Admin Dashboard'
weight: 20
flow:
- post:
url: '/api/auth/login'
json:
email: 'admin@test.com'
password: 'admin123'
capture:
- json: '$.token'
as: 'authToken'
- get:
url: '/api/admin/dashboard'
headers:
Authorization: 'Bearer {{ authToken }}'
- get:
url: '/api/admin/analytics'
headers:
Authorization: 'Bearer {{ authToken }}'
- name: 'API Health Checks'
weight: 20
flow:
- get:
url: '/health'
- get:
url: '/api/health'
Performance Monitoring Setup
// monitoring/performance-monitor.js
const prometheus = require('prom-client');
const express = require('express');
class PerformanceMonitor {
constructor() {
// Create metrics registry
this.register = new prometheus.Registry();
// Add default metrics
prometheus.collectDefaultMetrics({ register: this.register });
// Custom metrics
this.httpRequestDuration = new prometheus.Histogram({
name: 'http_request_duration_seconds',
help: 'Duration of HTTP requests in seconds',
labelNames: ['method', 'route', 'status_code'],
buckets: [0.1, 0.3, 0.5, 0.7, 1, 3, 5, 7, 10],
registers: [this.register]
});
this.httpRequestTotal = new prometheus.Counter({
name: 'http_requests_total',
help: 'Total number of HTTP requests',
labelNames: ['method', 'route', 'status_code'],
registers: [this.register]
});
this.activeConnections = new prometheus.Gauge({
name: 'active_connections',
help: 'Number of active connections',
registers: [this.register]
});
this.databaseQueryDuration = new prometheus.Histogram({
name: 'database_query_duration_seconds',
help: 'Duration of database queries in seconds',
labelNames: ['operation', 'table'],
buckets: [0.01, 0.05, 0.1, 0.3, 0.5, 1, 3, 5],
registers: [this.register]
});
this.memoryUsage = new prometheus.Gauge({
name: 'memory_usage_bytes',
help: 'Memory usage in bytes',
labelNames: ['type'],
registers: [this.register]
});
// Start memory monitoring
this.startMemoryMonitoring();
}
// Express middleware for HTTP metrics
getHttpMetricsMiddleware() {
return (req, res, next) => {
const startTime = Date.now();
res.on('finish', () => {
const duration = (Date.now() - startTime) / 1000;
const route = req.route?.path || req.path || 'unknown';
this.httpRequestDuration
.labels(req.method, route, res.statusCode.toString())
.observe(duration);
this.httpRequestTotal
.labels(req.method, route, res.statusCode.toString())
.inc();
});
next();
};
}
// Database query metrics
recordDatabaseQuery(operation, table, duration) {
this.databaseQueryDuration
.labels(operation, table)
.observe(duration / 1000); // Convert to seconds
}
// Connection metrics
incrementActiveConnections() {
this.activeConnections.inc();
}
decrementActiveConnections() {
this.activeConnections.dec();
}
// Memory monitoring
startMemoryMonitoring() {
setInterval(() => {
const memUsage = process.memoryUsage();
this.memoryUsage.labels('rss').set(memUsage.rss);
this.memoryUsage.labels('heapTotal').set(memUsage.heapTotal);
this.memoryUsage.labels('heapUsed').set(memUsage.heapUsed);
this.memoryUsage.labels('external').set(memUsage.external);
}, 5000); // Every 5 seconds
}
// Metrics endpoint
getMetricsHandler() {
return async (req, res) => {
res.set('Content-Type', this.register.contentType);
res.end(await this.register.metrics());
};
}
}
module.exports = PerformanceMonitor;
Performance Profiling
// profiling/cpu-profiler.js
const v8Profiler = require('v8-profiler-next');
const fs = require('fs');
const path = require('path');
class CPUProfiler {
constructor() {
this.profiles = new Map();
}
startProfiling(profileName = 'default') {
console.log(`Starting CPU profiling: ${profileName}`);
v8Profiler.startProfiling(profileName, true);
this.profiles.set(profileName, Date.now());
}
stopProfiling(profileName = 'default', outputDir = './profiles') {
const profile = v8Profiler.stopProfiling(profileName);
const startTime = this.profiles.get(profileName);
const duration = Date.now() - startTime;
console.log(`CPU profiling completed: ${profileName} (${duration}ms)`);
// Ensure output directory exists
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
// Save profile
const fileName = `cpu-profile-${profileName}-${Date.now()}.cpuprofile`;
const filePath = path.join(outputDir, fileName);
profile.export((error, result) => {
if (error) {
console.error('Error exporting CPU profile:', error);
return;
}
fs.writeFileSync(filePath, result);
console.log(`CPU profile saved: ${filePath}`);
});
profile.delete();
this.profiles.delete(profileName);
}
// Automatic profiling for slow requests
getProfilingMiddleware(threshold = 1000) {
return (req, res, next) => {
const startTime = Date.now();
const profileName = `request-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
res.on('finish', () => {
const duration = Date.now() - startTime;
if (duration > threshold) {
console.log(`Slow request detected: ${req.method} ${req.path} (${duration}ms)`);
// Profile similar requests in the future
this.scheduleProfilingForRoute(req.method, req.path);
}
});
next();
};
}
scheduleProfilingForRoute(method, path) {
// Implementation for scheduled profiling
console.log(`Scheduling profiling for ${method} ${path}`);
}
}
// Memory profiler
class MemoryProfiler {
constructor() {
this.snapshots = [];
}
takeHeapSnapshot(name = 'default') {
const snapshot = v8Profiler.takeSnapshot(name);
this.snapshots.push({ name, snapshot, timestamp: Date.now() });
return snapshot;
}
saveHeapSnapshot(snapshot, outputDir = './profiles') {
return new Promise((resolve, reject) => {
// Ensure output directory exists
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
const fileName = `heap-snapshot-${Date.now()}.heapsnapshot`;
const filePath = path.join(outputDir, fileName);
const writeStream = fs.createWriteStream(filePath);
snapshot.export()
.pipe(writeStream)
.on('finish', () => {
console.log(`Heap snapshot saved: ${filePath}`);
resolve(filePath);
})
.on('error', (error) => {
console.error('Error saving heap snapshot:', error);
reject(error);
});
});
}
compareSnapshots(snapshot1, snapshot2) {
// Simplified comparison - in practice, you'd use more sophisticated tools
console.log('Comparing heap snapshots...');
const diff = {
timestamp1: snapshot1.timestamp,
timestamp2: snapshot2.timestamp,
timeDiff: snapshot2.timestamp - snapshot1.timestamp,
// Add more detailed comparison logic here
};
return diff;
}
// Automatic memory monitoring
startMemoryMonitoring(interval = 30000) {
setInterval(() => {
const memUsage = process.memoryUsage();
const heapUsedMB = Math.round(memUsage.heapUsed / 1024 / 1024);
console.log(`Memory usage: ${heapUsedMB}MB heap used`);
// Take snapshot if memory usage is high
if (heapUsedMB > 500) { // 500MB threshold
console.log('High memory usage detected, taking heap snapshot');
const snapshot = this.takeHeapSnapshot(`high-memory-${Date.now()}`);
this.saveHeapSnapshot(snapshot);
}
}, interval);
}
}
module.exports = { CPUProfiler, MemoryProfiler };
Performance Testing CI/CD Integration
# .github/workflows/performance-test.yml
name: Performance Testing
on:
schedule:
- cron: '0 2 * * *' # Daily at 2 AM
workflow_dispatch:
inputs:
test_type:
description: 'Type of performance test'
required: true
default: 'load'
type: choice
options:
- load
- stress
- spike
- endurance
jobs:
performance-test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build application
run: npm run build
- name: Start application
run: |
npm start &
sleep 30 # Wait for app to start
- name: Install K6
run: |
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69
echo "deb 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
- name: Run Performance Tests
run: |
case "${{ github.event.inputs.test_type || 'load' }}" in
load)
k6 run --out json=results.json k6-tests/load-test-suite.js
;;
stress)
k6 run --out json=results.json k6-tests/stress-test.js
;;
spike)
k6 run --out json=results.json k6-tests/spike-test.js
;;
endurance)
k6 run --out json=results.json k6-tests/endurance-test.js
;;
esac
env:
BASE_URL: http://localhost:3000
- name: Generate Performance Report
run: |
node scripts/generate-performance-report.js results.json
- name: Upload Results
uses: actions/upload-artifact@v3
with:
name: performance-test-results
path: |
results.json
performance-report.html
performance-report.json
- name: Performance Regression Check
run: |
node scripts/check-performance-regression.js results.json
- name: Comment PR with Results
if: github.event_name == 'pull_request'
uses: actions/github-script@v6
with:
script: |
const fs = require('fs');
const report = JSON.parse(fs.readFileSync('performance-report.json', 'utf8'));
const comment = `## Performance Test Results
| Metric | Value | Threshold | Status |
|--------|-------|-----------|--------|
| Avg Response Time | ${report.avg_response_time}ms | <500ms | ${report.avg_response_time < 500 ? '✅' : '❌'} |
| P95 Response Time | ${report.p95_response_time}ms | <2000ms | ${report.p95_response_time < 2000 ? '✅' : '❌'} |
| Error Rate | ${report.error_rate}% | <1% | ${report.error_rate < 1 ? '✅' : '❌'} |
| Throughput | ${report.throughput} RPS | >100 RPS | ${report.throughput > 100 ? '✅' : '❌'} |
[View detailed report](${report.report_url})
`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
});
Performance Optimization Recommendations
// scripts/performance-analyzer.js
class PerformanceAnalyzer {
constructor() {
this.recommendations = [];
}
analyzeResults(testResults) {
const analysis = {
responseTimeAnalysis: this.analyzeResponseTime(testResults),
throughputAnalysis: this.analyzeThroughput(testResults),
errorAnalysis: this.analyzeErrors(testResults),
resourceAnalysis: this.analyzeResourceUsage(testResults),
};
this.generateRecommendations(analysis);
return {
analysis,
recommendations: this.recommendations,
};
}
analyzeResponseTime(results) {
const responseTimes = results.metrics.http_req_duration.values;
return {
average: responseTimes.avg,
p50: responseTimes.p50,
p90: responseTimes.p90,
p95: responseTimes.p95,
p99: responseTimes.p99,
max: responseTimes.max,
isWithinSLA: responseTimes.p95 < 2000, // 2 second SLA
};
}
analyzeThroughput(results) {
const requestRate = results.metrics.http_reqs.rate;
return {
requestsPerSecond: requestRate,
totalRequests: results.metrics.http_reqs.count,
isWithinTarget: requestRate > 100, // 100 RPS target
};
}
analyzeErrors(results) {
const errorRate = results.metrics.http_req_failed.rate * 100;
return {
errorRate,
totalErrors: results.metrics.http_req_failed.count,
isWithinTarget: errorRate < 1, // 1% error rate target
};
}
analyzeResourceUsage(results) {
// This would typically come from monitoring data
return {
cpuUsage: results.monitoring?.cpu_usage || 0,
memoryUsage: results.monitoring?.memory_usage || 0,
diskIO: results.monitoring?.disk_io || 0,
networkIO: results.monitoring?.network_io || 0,
};
}
generateRecommendations(analysis) {
this.recommendations = [];
// Response time recommendations
if (!analysis.responseTimeAnalysis.isWithinSLA) {
this.recommendations.push({
category: 'Response Time',
severity: 'High',
issue: `P95 response time (${analysis.responseTimeAnalysis.p95}ms) exceeds SLA`,
recommendations: [
'Implement database query optimization',
'Add caching layer (Redis/Memcached)',
'Optimize API endpoint logic',
'Consider implementing CDN for static assets',
],
});
}
// Throughput recommendations
if (!analysis.throughputAnalysis.isWithinTarget) {
this.recommendations.push({
category: 'Throughput',
severity: 'Medium',
issue: `Request rate (${analysis.throughputAnalysis.requestsPerSecond} RPS) below target`,
recommendations: [
'Scale horizontally by adding more server instances',
'Implement connection pooling',
'Optimize application startup time',
'Review and optimize middleware chain',
],
});
}
// Error rate recommendations
if (!analysis.errorAnalysis.isWithinTarget) {
this.recommendations.push({
category: 'Reliability',
severity: 'Critical',
issue: `Error rate (${analysis.errorAnalysis.errorRate}%) exceeds threshold`,
recommendations: [
'Implement circuit breaker pattern',
'Add retry logic with exponential backoff',
'Improve error handling and logging',
'Review database connection management',
],
});
}
// Resource usage recommendations
if (analysis.resourceAnalysis.cpuUsage > 80) {
this.recommendations.push({
category: 'Resource Usage',
severity: 'High',
issue: `High CPU usage (${analysis.resourceAnalysis.cpuUsage}%)`,
recommendations: [
'Profile application to identify CPU bottlenecks',
'Implement async processing for heavy operations',
'Consider CPU scaling or optimization',
'Review algorithm complexity in hot paths',
],
});
}
if (analysis.resourceAnalysis.memoryUsage > 80) {
this.recommendations.push({
category: 'Resource Usage',
severity: 'High',
issue: `High memory usage (${analysis.resourceAnalysis.memoryUsage}%)`,
recommendations: [
'Implement memory profiling to identify leaks',
'Optimize data structures and caching',
'Consider memory scaling',
'Review garbage collection settings',
],
});
}
}
}
module.exports = PerformanceAnalyzer;
This performance testing expert provides comprehensive strategies and implementations for identifying bottlenecks, measuring performance metrics, and optimizing application performance across different load scenarios.