Skip to content
Plurafy

Load Testing and Performance Benchmarking

Load testing validates application performance under stress. Learn to design and execute load tests and interpret results for optimization.

Conduct comprehensive load testing to identify bottlenecks, validate performance targets, and ensure system reliability under peak load.

  • Smoke Testing: Basic functionality
  • Load Testing: Normal peak load
  • Stress Testing: Beyond capacity
  • Endurance Testing: Long-duration testing
  • Spike Testing: Sudden load changes
  • Throughput: Requests per second
  • Response Time: Average, P95, P99
  • Error Rate: Failed requests percentage
  • Resource Usage: CPU, memory, connections
Terminal window
# Install Artillery
npm install -g artillery
# Simple load test
artillery quick --count 100 --num 10 https://api.example.com
# Config-based test
artillery run load-test-config.yml --target https://api.example.com
load-test-config.yml
config:
target: "https://api.example.com"
phases:
- duration: 60
arrivalRate: 10
name: "Warm up"
- duration: 120
arrivalRate: 50
name: "Sustained load"
- duration: 60
arrivalRate: 100
name: "Peak load"
- duration: 60
arrivalRate: 10
name: "Cool down"
processor: "./load-test-processor.js"
variables:
userIds: []
scenarios:
- name: "Get users"
flow:
- get:
url: "/api/users"
- think: 3
- get:
url: "/api/users/{{ id }}"
- name: "Create user"
flow:
- post:
url: "/api/users"
json:
email: "user{{ $randomNumber(1, 10000) }}@example.com"
name: "Test User"
expect:
- statusCode: 201
- name: "Update user"
flow:
- put:
url: "/api/users/1"
json:
name: "Updated Name"
expect:
- statusCode: 200
const axios = require('axios');
class PerformanceBenchmark {
constructor(options = {}) {
this.baseURL = options.baseURL || 'http://localhost:3000';
this.duration = options.duration || 60000; // 1 minute
this.concurrency = options.concurrency || 10;
this.results = {
requests: [],
errors: [],
totalRequests: 0,
totalErrors: 0,
startTime: null,
endTime: null,
};
}
async runBenchmark(endpoints) {
console.log(`Starting benchmark: ${this.duration}ms with ${this.concurrency} concurrency`);
this.results.startTime = Date.now();
const endTime = this.results.startTime + this.duration;
const tasks = [];
for (let i = 0; i < this.concurrency; i++) {
tasks.push(this.worker(endpoints, endTime));
}
await Promise.all(tasks);
this.results.endTime = Date.now();
this.printResults();
}
async worker(endpoints, endTime) {
while (Date.now() < endTime) {
const endpoint = endpoints[Math.floor(Math.random() * endpoints.length)];
try {
const startTime = Date.now();
if (endpoint.method === 'POST') {
await axios.post(`${this.baseURL}${endpoint.path}`, endpoint.data);
} else {
await axios.get(`${this.baseURL}${endpoint.path}`);
}
const duration = Date.now() - startTime;
this.results.requests.push({
endpoint: endpoint.path,
duration,
timestamp: new Date(),
statusCode: 200,
});
this.results.totalRequests++;
} catch (error) {
this.results.errors.push({
endpoint: endpoint.path,
error: error.message,
statusCode: error.response?.status,
});
this.results.totalErrors++;
}
}
}
printResults() {
const durations = this.results.requests.map(r => r.duration);
const avg = durations.reduce((a, b) => a + b, 0) / durations.length;
const sorted = durations.sort((a, b) => a - b);
const p95 = sorted[Math.floor(sorted.length * 0.95)];
const p99 = sorted[Math.floor(sorted.length * 0.99)];
const max = Math.max(...durations);
const min = Math.min(...durations);
const totalTime = this.results.endTime - this.results.startTime;
const throughput = (this.results.totalRequests / (totalTime / 1000)).toFixed(2);
console.log(`
Benchmark Results:
==================
Total Requests: ${this.results.totalRequests}
Total Errors: ${this.results.totalErrors}
Error Rate: ${((this.results.totalErrors / this.results.totalRequests) * 100).toFixed(2)}%
Throughput: ${throughput} req/s
Response Times (ms):
- Average: ${avg.toFixed(2)}
- Min: ${min}
- Max: ${max}
- P95: ${p95}
- P99: ${p99}
`);
}
}
// Usage
const benchmark = new PerformanceBenchmark({
baseURL: 'http://localhost:3000',
duration: 60000,
concurrency: 10,
});
const endpoints = [
{ path: '/api/users', method: 'GET' },
{ path: '/api/posts', method: 'GET' },
{ path: '/api/users', method: 'POST', data: { name: 'Test', email: 'test@example.com' } },
];
await benchmark.runBenchmark(endpoints);
const { performance } = require('perf_hooks');
class LocalBenchmark {
static async compare(name, fn1, fn2, iterations = 10000) {
// Benchmark function 1
const start1 = performance.now();
for (let i = 0; i < iterations; i++) {
await fn1();
}
const time1 = performance.now() - start1;
// Benchmark function 2
const start2 = performance.now();
for (let i = 0; i < iterations; i++) {
await fn2();
}
const time2 = performance.now() - start2;
console.log(`
${name}:
- Function 1: ${(time1 / iterations).toFixed(4)}ms per call
- Function 2: ${(time2 / iterations).toFixed(4)}ms per call
- Difference: ${Math.abs(time1 - time2).toFixed(2)}ms (${((Math.max(time1, time2) / Math.min(time1, time2)).toFixed(2))}x)
`);
}
}
// Example: Compare array methods
LocalBenchmark.compare(
'Array methods',
async () => {
const arr = Array(1000).fill(0).map((_, i) => i);
return arr.map(x => x * 2);
},
async () => {
const arr = Array(1000).fill(0).map((_, i) => i);
return arr.reduce((acc, x) => [...acc, x * 2], []);
},
1000
);
class LoadTestReportGenerator {
constructor(results) {
this.results = results;
}
generateHTML() {
const stats = this.calculateStats();
return `
<!DOCTYPE html>
<html>
<head>
<title>Load Test Report</title>
<style>
body { font-family: Arial; margin: 20px; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #4CAF50; color: white; }
</style>
</head>
<body>
<h1>Load Test Report</h1>
<h2>Summary</h2>
<table>
<tr>
<th>Metric</th>
<th>Value</th>
</tr>
<tr>
<td>Total Requests</td>
<td>${stats.totalRequests}</td>
</tr>
<tr>
<td>Successful Requests</td>
<td>${stats.totalRequests - stats.totalErrors}</td>
</tr>
<tr>
<td>Failed Requests</td>
<td>${stats.totalErrors}</td>
</tr>
<tr>
<td>Error Rate</td>
<td>${stats.errorRate.toFixed(2)}%</td>
</tr>
<tr>
<td>Throughput</td>
<td>${stats.throughput.toFixed(2)} req/s</td>
</tr>
</table>
<h2>Response Times</h2>
<table>
<tr>
<th>Metric</th>
<th>Value (ms)</th>
</tr>
<tr>
<td>Average</td>
<td>${stats.avg.toFixed(2)}</td>
</tr>
<tr>
<td>P50</td>
<td>${stats.p50}</td>
</tr>
<tr>
<td>P95</td>
<td>${stats.p95}</td>
</tr>
<tr>
<td>P99</td>
<td>${stats.p99}</td>
</tr>
<tr>
<td>Min</td>
<td>${stats.min}</td>
</tr>
<tr>
<td>Max</td>
<td>${stats.max}</td>
</tr>
</table>
</body>
</html>
`;
}
calculateStats() {
const durations = this.results.requests.map(r => r.duration);
const sorted = durations.sort((a, b) => a - b);
const totalTime = (this.results.endTime - this.results.startTime) / 1000;
return {
totalRequests: this.results.totalRequests,
totalErrors: this.results.totalErrors,
errorRate: (this.results.totalErrors / this.results.totalRequests) * 100,
throughput: this.results.totalRequests / totalTime,
avg: durations.reduce((a, b) => a + b, 0) / durations.length,
p50: sorted[Math.floor(sorted.length * 0.5)],
p95: sorted[Math.floor(sorted.length * 0.95)],
p99: sorted[Math.floor(sorted.length * 0.99)],
min: Math.min(...durations),
max: Math.max(...durations),
};
}
saveReport(filename) {
const fs = require('fs');
fs.writeFileSync(filename, this.generateHTML());
console.log(`Report saved to ${filename}`);
}
}
  1. Test Design

    • Use realistic scenarios
    • Test different endpoints
    • Vary request types
    • Simulate real user behavior
  2. Environment

    • Test in production-like environment
    • Isolate from other traffic
    • Control external dependencies
    • Document test conditions
  3. Analysis

    • Focus on P95/P99 latency
    • Monitor error rates
    • Track resource usage
    • Compare against baselines
  4. Interpretation

    • Identify bottlenecks
    • Find breaking points
    • Understand bottleneck causes
    • Plan improvements
  5. Automation

    • Automate test execution
    • Generate reports
    • Track trends
    • Integrate with CI/CD
  • Capacity Planning: Determine infrastructure needs
  • Regression Testing: Detect performance regressions
  • Optimization: Identify improvement areas
  • Release Validation: Verify performance before deployment
  • SLA Verification: Ensure service meets commitments