API/应用响应时间测试
测试响应时间的不同层面
1. HTTP/API响应时间测试
使用curl测试
# 基本响应时间测试
curl -w "\nTotal: %{time_total}s\nConnect: %{time_connect}s\nTTFB: %{time_starttransfer}s\n" -o /dev/null -s https://api.example.com/endpoint
# 重复测试多次取平均值
for i in {1..10}; do curl -w "%{time_total}\n" -o /dev/null -s https://api.example.com/endpoint; done | awk '{total+=$1} END {print "Average: " total/NR "s"}'
使用ab工具(Apache Benchmark)
# 安装(Windows可通过WSL或直接下载)
# Ubuntu/Debian: apt-get install apache2-utils
# 执行1000次请求,10个并发
ab -n 1000 -c 10 https://api.example.com/endpoint
2. 使用Node.js进行API测试
const axios = require('axios');
const { performance } = require('perf_hooks');
async function testResponseTime() {
const iterations = 100;
let totalTime = 0;
const responseTimes = [];
for (let i = 0; i < iterations; i++) {
const start = performance.now();
try {
await axios.get('https://api.example.com/endpoint');
const end = performance.now();
const time = (end - start) / 1000; // 转换为秒
responseTimes.push(time);
totalTime += time;
} catch (error) {
console.error(`请求失败: ${error.message}`);
}
}
responseTimes.sort((a, b) => a - b);
console.log(`平均响应时间: ${(totalTime / iterations).toFixed(4)}s`);
console.log(`最小响应时间: ${Math.min(...responseTimes).toFixed(4)}s`);
console.log(`最大响应时间: ${Math.max(...responseTimes).toFixed(4)}s`);
console.log(`P50响应时间: ${responseTimes[Math.floor(iterations * 0.5)].toFixed(4)}s`);
console.log(`P95响应时间: ${responseTimes[Math.floor(iterations * 0.95)].toFixed(4)}s`);
console.log(`P99响应时间: ${responseTimes[Math.floor(iterations * 0.99)].toFixed(4)}s`);
}
testResponseTime();
3. 数据库查询响应时间测试
PostgreSQL查询时间测试
-- 方法1: 使用EXPLAIN ANALYZE
EXPLAIN ANALYZE SELECT * FROM users WHERE created_at > '2023-01-01' LIMIT 100;
-- 方法2: 使用psql的计时功能
\timing on
SELECT * FROM users WHERE created_at > '2023-01-01' LIMIT 100;
\timing off
在Node.js中测试数据库查询时间
async function testDbQueryTime() {
const startTime = performance.now();
// 使用TypeORM示例
const users = await userRepository.find({
where: { created_at: MoreThan('2023-01-01') },
take: 100
});
const endTime = performance.now();
const queryTime = (endTime - startTime) / 1000; // 转换为秒
console.log(`数据库查询耗时: ${queryTime.toFixed(4)}s`);
return users;
}
4. 使用专业工具进行负载测试
JMeter
- 下载安装JMeter:Apache JMeter官网
- 创建测试计划:添加线程组、HTTP请求、监听器
- 配置参数:线程数、循环次数、请求参数
- 运行测试并分析结果:响应时间图表、吞吐量、错误率
k6
# 安装k6
# Windows: choco install k6
# 或下载安装包
# 创建测试脚本 test.js
cat > test.js << 'EOF'
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
stages: [
{ duration: '1m', target: 10 }, // 1分钟内从0增加到10个并发用户
{ duration: '3m', target: 10 }, // 保持10个并发用户3分钟
{ duration: '1m', target: 0 }, // 1分钟内减少到0个并发用户
],
thresholds: {
'http_req_duration': ['p(95)<500'], // 95%的请求响应时间应小于500ms
},
};
export default function() {
const res = http.get('https://api.example.com/endpoint');
check(res, {
'is status 200': (r) => r.status === 200,
});
sleep(1);
}
EOF
# 运行测试
k6 run test.js
5. NestJS应用中的响应时间测试
使用中间件测量响应时间
// src/common/response-time.middleware.ts
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
@Injectable()
export class ResponseTimeMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
const start = Date.now();
res.on('finish', () => {
const time = Date.now() - start;
console.log(`[${req.method}] ${req.url} - ${time}ms`);
// 可以记录到日志系统或监控系统
// 也可以设置阈值报警
if (time > 500) {
console.warn(`⚠️ 慢请求警告: ${req.method} ${req.url} - ${time}ms`);
}
});
next();
}
}
在app.module中使用中间件
// src/app.module.ts
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
import { ResponseTimeMiddleware } from './common/response-time.middleware';
@Module({
imports: [],
controllers: [],
providers: [],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(ResponseTimeMiddleware)
.forRoutes('*'); // 应用到所有路由
}
}
6. 监控与分析工具
使用Prometheus + Grafana监控
// NestJS中集成Prometheus
import { PrometheusModule } from '@willsoto/nestjs-prometheus';
@Module({
imports: [
PrometheusModule.register(),
// 其他模块
],
})
export class AppModule {}
使用New Relic或Datadog进行APM监控
- 安装对应SDK
- 配置监控参数
- 查看实时响应时间图表和报警
7. 测试最佳实践
- 基准测试:先建立性能基准,再进行优化
- 隔离测试:分别测试网络、数据库、应用逻辑等不同环节
- 负载测试:模拟真实用户负载,观察系统表现
- 持续监控:设置长期监控,观察性能趋势
- 多维度指标:同时关注响应时间、吞吐量、错误率等指标
- 分位数分析:关注P50/P95/P99等不同分位数的响应时间
- 自动化测试:将性能测试集成到CI/CD流程中
8. 示例:综合测试脚本
// 完整的API测试脚本(支持GET、POST请求和请求头设定)
const axios = require('axios');
const { performance } = require('perf_hooks');
const fs = require('fs');
async function runLoadTest(baseUrl, endpoints, concurrentUsers, requestsPerUser) {
const results = {};
for (const endpoint of endpoints) {
// 支持字符串形式的endpoint(默认GET)和对象形式的endpoint(可指定method、path、data和headers)
const method = endpoint.method || 'GET';
const path = endpoint.path || endpoint;
const data = endpoint.data || null;
const headers = endpoint.headers || {};
console.log(`测试端点: ${method} ${path}`);
const url = `${baseUrl}${path}`;
const allTimes = [];
const errors = [];
// 模拟并发用户
const promises = [];
for (let u = 0; u < concurrentUsers; u++) {
promises.push((async () => {
for (let r = 0; r < requestsPerUser; r++) {
const start = performance.now();
try {
// 构建axios请求配置,包含headers
const config = { headers };
// 根据method决定使用GET还是POST
if (method.toUpperCase() === 'POST') {
// POST请求,发送data数据和headers
await axios.post(url, data, config);
} else {
// 其他请求默认为GET,使用headers
await axios.get(url, config);
}
const end = performance.now();
allTimes.push(end - start);
} catch (error) {
errors.push(error.message);
}
// 随机延迟模拟真实用户行为
await new Promise(resolve => setTimeout(resolve, Math.random() * 1000));
}
})());
}
await Promise.all(promises);
// 计算统计数据
allTimes.sort((a, b) => a - b);
const totalRequests = allTimes.length + errors.length;
// 使用method+path作为结果对象的key
const resultKey = `${method} ${path}`;
results[resultKey] = {
method,
path,
hasHeaders: Object.keys(headers).length > 0,
totalRequests,
successfulRequests: allTimes.length,
errorCount: errors.length,
errorRate: (errors.length / totalRequests * 100).toFixed(2) + '%',
avgResponseTime: (allTimes.reduce((a, b) => a + b, 0) / allTimes.length).toFixed(2) + 'ms',
minResponseTime: Math.min(...allTimes).toFixed(2) + 'ms',
maxResponseTime: Math.max(...allTimes).toFixed(2) + 'ms',
p50: allTimes[Math.floor(allTimes.length * 0.5)].toFixed(2) + 'ms',
p95: allTimes[Math.floor(allTimes.length * 0.95)].toFixed(2) + 'ms',
p99: allTimes[Math.floor(allTimes.length * 0.99)].toFixed(2) + 'ms',
};
console.log(results[endpoint]);
}
// 保存结果到文件
fs.writeFileSync('test-results.json', JSON.stringify(results, null, 2));
console.log('测试结果已保存到 test-results.json');
}
// 运行测试(示例包含GET和POST请求)
runLoadTest(
'http://localhost:3000',
[
// GET请求示例(字符串形式,向后兼容)
'/square/posts',
'/square/hot-posts?limit=10',
'/chat/userChatMenu',
// POST请求示例(对象形式)
{
method: 'POST',
path: '/auth/login',
data: {
username: 'testuser',
password: 'testpassword'
}
},
{
method: 'POST',
path: '/chat/createChat',
data: {
title: '测试对话',
userId: 1
},
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer test-token'
}
},
// GET请求带自定义请求头示例
{
method: 'GET',
path: '/user/profile',
headers: {
'Authorization': 'Bearer test-token',
'Accept': 'application/json'
}
}
],
10, // 并发用户数
50 // 每用户请求数
);
通过这些方法,您可以全面测试和监控API响应时间,确保系统性能满足要求,并及时发现和解决性能瓶颈。