以下是基于 Node.js 的性能测试完整示例,演示如何对一个 REST API 进行压力测试,分析响应时间、吞吐量和资源消耗,并定位性能瓶颈。
1. 场景描述
假设有一个用户查询接口 GET /api/users/:id
,需要测试其在以下场景下的表现:
- 高并发请求:模拟 1000 个用户每秒(RPS)的访问量。
- 长时稳定性:持续运行 5 分钟,观察内存泄漏和错误率。
- 依赖分析:接口依赖 MongoDB 数据库和 Redis 缓存。
2. 工具选择
工具 |
作用 |
k6 |
开源性能测试工具,支持脚本化和云原生场景,适合高并发压测。 |
autocannon |
轻量级 HTTP 压测工具,适合快速本地测试。 |
PM2 |
进程管理工具,监控 Node.js 应用的 CPU/内存使用。 |
MongoDB Atlas |
托管数据库服务,提供性能监控指标(如查询延迟、连接数)。 |
Docker |
隔离测试环境,确保压测不影响本地开发环境。 |
3. 性能测试实现步骤
步骤 1:准备待测试的 API
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const express = require("express"); const { getDb } = require("./db"); const app = express();
app.get("/api/users/:id", async (req, res) => { try { const user = await getDb().collection("users").findOne({ _id: req.params.id }); res.json(user || { error: "User not found" }); } catch (error) { res.status(500).json({ error: "Database error" }); } });
const server = app.listen(3000, () => console.log("Server running on port 3000")); module.exports = server;
|
步骤 2:编写 k6 性能测试脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import http from 'k6/http'; import { check, sleep } from 'k6';
export const options = { stages: [ { duration: '30s', target: 500 }, { duration: '2m', target: 1000 }, { duration: '30s', target: 0 }, ], thresholds: { http_req_duration: ['p(95)<500'], http_req_failed: ['rate<0.01'], }, };
export default function () { const userId = '507f191e810c19729de860ea'; const res = http.get(`http://localhost:3000/api/users/${userId}`); check(res, { 'Status is 200': (r) => r.status === 200, 'Has valid user data': (r) => JSON.parse(r.body).name !== undefined, }); sleep(1); }
|
步骤 3:运行测试并监控资源
1 2 3 4 5 6 7 8
| pm2 start src/app.js --name "user-api"
k6 run tests/performance/user-load-test.js
pm2 monit
|
4. 性能测试结果分析
(1) k6 输出报告
1 2 3 4 5 6 7
| ✓ Status is 200 ✓ Has valid user data
checks.....................: 99.8% ✓ 89910 ✗ 180 http_req_duration.........: avg=220ms min=50ms med=180ms max=1.2s p(95)=450ms http_reqs..................: 90090 (≈ 1001.0 RPS) iteration_duration.........: avg=1.22s min=1.01s med=1.18s max=2.5s
|
- 关键指标:
- 吞吐量(RPS):1001 请求/秒。
- 95% 响应时间:450ms。
- 错误率:0.2%(180次失败)。
(2) PM2 资源监控
1 2
| CPU Usage: 85% (~90% during peak) Memory Usage: 512MB (稳定,无泄漏)
|
(3) MongoDB Atlas 监控
- 查询延迟:平均 150ms,峰值 300ms。
- 连接数:峰值 200 个连接。
5. 性能瓶颈定位与优化
瓶颈 1:数据库查询延迟过高
- 根因:未对
_id
字段建立索引。
- 优化:
1 2
| db.users.createIndex({ _id: 1 });
|
瓶颈 2:Node.js CPU 接近满载
- 根因:同步阻塞操作(如未缓存的 JWT 验证)。
- 优化:
1 2 3 4 5 6 7 8 9 10
| app.get("/api/users/:id", async (req, res) => { const cachedUser = await redis.get(`user:${req.params.id}`); if (cachedUser) return res.json(JSON.parse(cachedUser)); const user = await db.collection("users").findOne({ _id: req.params.id }); await redis.set(`user:${req.params.id}`, JSON.stringify(user), 'EX', 60); res.json(user); });
|
瓶颈 3:HTTP 连接池不足
- 根因:Node.js 默认的
http.globalAgent
限制连接数。
- 优化:
1 2 3
| const http = require('http'); http.globalAgent.maxSockets = 1000;
|
6. 优化后复测结果
1 2 3
| http_req_duration.........: avg=80ms min=30ms med=70ms max=300ms p(95)=120ms http_reqs..................: 90090 (≈ 2500 RPS) CPU Usage.................: 45% (下降约50%)
|
7. 工具链扩展
场景 |
工具 |
用途 |
分布式压测 |
k6 Cloud |
模拟全球用户分布,生成可视化报告。 |
内存泄漏检测 |
Node.js Inspector + Chrome DevTools |
分析堆内存快照。 |
日志分析 |
ELK Stack |
聚合压测期间的错误日志,定位异常。 |
全链路监控 |
Prometheus + Grafana |
监控微服务链路中各组件(API、DB、缓存)。 |
总结
通过性能测试,可以:
- 量化系统能力:确定服务的最大吞吐量和临界负载。
- 暴露瓶颈:识别代码、数据库或基础设施的性能短板。
- 验证优化效果:通过对比测试数据,确认优化措施的有效性。
最佳实践:
- 基准测试(Baseline):在每次重大变更后运行性能测试,建立历史数据对比。
- 自动化流水线:将性能测试集成到 CI/CD,设置阈值拦截性能退化。
- 生产环境影子测试:通过流量复制(如 GoReplay),在生产环境安全压测。
以下是 k6 和 PM2 的安装方法,支持 macOS、Linux 和 Windows 系统:
1. 安装 k6(性能测试工具)
k6 支持多种安装方式,根据操作系统选择以下任一方法:
macOS
Linux (Debian/Ubuntu)
1 2 3 4 5 6
| 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
|
Windows
- 访问 k6 官网下载页面。
- 下载
.msi
安装包并双击运行。
- 安装完成后,打开 PowerShell 验证:
或者 choco install k6
验证安装
2. 安装 PM2(Node.js 进程管理工具)
PM2 是一个 Node.js 进程管理器,需通过 npm 全局安装:
所有操作系统
1 2 3 4 5 6
| npm install pm2@latest -g
pm2 --version
|
权限问题处理(Linux/macOS)
如果安装时提示权限不足,可使用 sudo
或修复 npm 目录权限:
1 2 3 4 5 6 7 8 9
| sudo npm install pm2@latest -g
mkdir ~/.npm-global npm config set prefix '~/.npm-global' echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc source ~/.bashrc npm install pm2@latest -g
|
3. 常见问题
k6 安装失败
- 网络问题:尝试使用镜像源(如国内用户):
1 2 3
| export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles brew install k6
|
- 手动下载:从 k6 Releases 下载二进制文件,解压后添加到
PATH
。
PM2 命令未找到
- 环境变量问题:确保 npm 全局目录(如
~/.npm-global/bin
)已添加到 PATH
。1 2
| echo 'export PATH=$PATH:~/.npm-global/bin' >> ~/.bashrc source ~/.bashrc
|
4. 使用示例
启动 Node.js 服务并监控
1 2
| pm2 start app.js --name "my-api" --watch pm2 monit
|
运行 k6 性能测试
通过以上步骤,可快速安装并验证 k6 和 PM2 的可用性。