JMeter压力测试实战:100并发压测模拟电商API的完整过程(附脚本与报告)
# JMeter压力测试实战:100并发压测模拟电商API的完整过程(附脚本与报告)
> 【摘要】网上讲 JMeter 的文章很多,但真正从头到尾跑一遍的少。本文在一个干净的 Linux 环境里,从安装 JMeter、搭建被测服务、编写含参数化与断言的测试计划,到命令行压测出报告,完整走了一遍,900 个样本 0 错误。文中附完整脚本与压测数据,可照着复现。
## 一、为什么要"温柔地"压测自己的服务
压力测试的目的不是把服务器打趴下,而是:
- **发现瓶颈**:找到系统的"最短木板"
- **验证容量**:知道系统能承受多少用户
- **建立基线**:为后续性能优化提供数据支持
本文实践的环境:
| 项目 | 版本/说明 |
|------|----------|
| 操作系统 | Huawei Cloud EulerOS 3.0 (aarch64) |
| Java | OpenJDK 17 |
| JMeter | Apache JMeter 5.6.3 |
| 被测服务 | Python 自建模拟电商 API |
## 二、第1步:安装 JMeter
JMeter 是纯 Java 应用,装好 Java 后解压即用:
```bash
# 先检查 Java 环境
java -version
# openjdk version "17" ...
# 下载 JMeter(国内推荐华为云镜像,速度快很多)
curl -L -o jmeter.tgz \
https://mirrors.huaweicloud.com/apache/jmeter/binaries/apache-jmeter-5.6.3.tgz
# 解压并验证
tar -xzf jmeter.tgz
mv apache-jmeter-5.6.3 /opt/jmeter
/opt/jmeter/bin/jmeter --version
```
**踩坑提醒**:官方 dlcdn 源国内访问很慢甚至超时,换华为云镜像后 83MB 几秒下完。另外解压路径别带中文,否则配置文件读写可能出乱码问题。
## 三、第2步:搭建被测服务(模拟电商 API)
没有真实系统怎么练手?自己写一个。用 Python 标准库搭一个模拟电商 API,包含三个接口:
- `POST /api/login` —— 登录,返回 token
- `GET /api/product` —— 浏览商品列表
- `POST /api/order` —— 下单(需要 token 鉴权)
```python
# mock_ecommerce_api.py(节选,完整代码见文末说明)
import json, random, threading, time
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
USERS = {
"zhangsan123": ("zhangsan", 1001),
"lisi456": ("lisi", 1002),
"wangwu789": ("wangwu", 1003),
}
tokens = set()
class Handler(BaseHTTPRequestHandler):
def do_POST(self):
if self.path == "/api/login":
# 模拟业务处理耗时 20~80ms
time.sleep(random.uniform(0.02, 0.08))
...
self._send(200, {"success": True,
"userId": user[0],
"access_token": token})
elif self.path == "/api/order":
# 模拟下单耗时 50~150ms,校验 token
...
class Server(ThreadingHTTPServer):
daemon_threads = True
Server(("127.0.0.1", 8080), Handler).serve_forever()
```
接口里故意加了 `time.sleep()` 模拟真实业务耗时——压测一个秒回的服务是没有意义的。
启动并验证:
```bash
python3 mock_ecommerce_api.py &
curl -s -X POST http://127.0.0.1:8080/api/login \
-H "Content-Type: application/json" \
-d '{"username":"张三","password":"zhangsan123"}'
# {"success": true, "userId": "zhangsan", "access_token": "tk-zhangsan-67062"}
```
## 四、第3步:参数化数据——让每个虚拟用户都不一样
真实用户不会都用同一个账号。创建 `users.csv`:
```csv
username,password,productId
张三,zhangsan123,1001
李四,lisi456,1002
王五,wangwu789,1003
...(共300行)
```
在 JMeter 测试计划中添加 **CSV 数据文件设置**:
```
文件名:/path/to/users.csv
编码:UTF-8
变量名:username,password,productId
是否允许带引号:false
遇到文件结束再次循环:true
线程共享模式:全部线程
```
**注意**:中文数据一定要指定 UTF-8 编码,否则 POST 出去的中文用户名会变问号。
## 五、第4步:测试计划设计
测试计划的结构(对应 JMeter 的树形组件):
```
测试计划:双十一压力测试
└── 线程组:100个虚拟用户(Ramp-up 10秒,循环3次)
├── CSV数据文件设置:users.csv
├── 登录请求(POST /api/login)
│ ├── HTTP信息头管理器:Content-Type: application/json
│ ├── JSON提取器:$.access_token → 变量 token
│ └── 响应断言:包含 "success": true
├── 浏览商品(GET /api/product)
│ └── 响应断言:包含 "success": true
├── 下单请求(POST /api/order)
│ ├── HTTP信息头管理器:Content-Type + Authorization: Bearer ${token}
│ ├── 响应断言:包含 "success": true
│ └── 持续时间断言:3000毫秒(超3秒即失败)
├── 高斯随机定时器:偏差200ms,固定延迟1000ms
└── 聚合报告(监听器)
```
几个关键设计点:
**1. 关联提取**:登录拿到的 token 要传给下单请求。用 JSON 提取器配置 `$.access_token`,下游请求头里写 `Bearer ${token}`,就完成了接口串联。
**2. 断言**:光返回 200 不代表业务成功,加响应断言检查 `"success": true`;再加持续时间断言 3000ms,响应超 3 秒直接判失败——这是给服务器划的红线。
**3. 高斯随机定时器**:偏差 200ms + 固定延迟 1000ms,即每个请求前等待 1000±200ms。**没有思考时间的压测等于机器人 DDos,有思考时间的压测才像真人**。
**4. 循环渐进**:先 5 线程冒烟验证脚本,确认 0 错误后再上 100 线程,一上来就全量压测,脚本有错都不知道错在哪。
## 六、第5步:命令行压测与报告
正式压测别用 GUI(GUI 里的监听器很吃资源),用非 GUI 模式 + 自动生成 HTML 报告:
```bash
/opt/jmeter/bin/jmeter -n -t double11_test.jmx \
-l result.jtl -e -o report
```
参数说明:`-n` 非图形模式,`-t` 指定测试计划,`-l` 结果文件,`-e` 压测结束后生成报告,`-o` 报告输出目录。
控制台实时输出:
```
summary + 84 in 00:00:05 = 17.3/s Avg: 54 ... Err: 0 (0.00%)
summary + 816 in 00:00:15 = 55.6/s Avg: 62 ... Err: 0 (0.00%)
summary = 900 in 00:00:20 = 46.1/s Avg: 62 Min: 11 Max: 177 Err: 0 (0.00%)
```
## 七、压测结果分析
| 请求名称 | 样本数 | 错误率 | 平均(ms) | 最小(ms) | 最大(ms) | 90%线(ms) | 95%线(ms) | 99%线(ms) | 吞吐量(/s) |
|---------|-------:|-------:|---------:|---------:|---------:|----------:|----------:|----------:|-----------:|
| 登录请求 | 300 | 0.00% | 52 | 22 | 112 | 76 | 79 | 82 | 18.8 |
| 浏览商品 | 300 | 0.00% | 32 | 11 | 68 | 47 | 49 | 54 | 18.8 |
| 下单请求 | 300 | 0.00% | 102 | 52 | 177 | 146 | 149 | 153 | 18.7 |
| **Total** | **900** | **0.00%** | **62** | **11** | **177** | **121** | **139** | **151** | **49.6** |
按性能测试的通用红线逐条检查:
1. **响应时间 > 3 秒?** 否。最大 177ms,持续时间断言零失败
2. **错误率 > 0.1%?** 否。900 样本 0 错误,登录提取 token → 下单鉴权的链路全部走通
3. **吞吐量上不去?** 49.6/s 看着不高,但这是被 1000±200ms 思考时间"压"出来的——这正是模拟真人的代价。去掉定时器重跑,吞吐量会直接取决于服务器容量
**结论**:被测服务在 100 并发下表现稳定,瓶颈在人为模拟的思考时间而非服务器本身,可以作为后续扩容压测的基线数据。
`report/index.html` 里还有响应时间随时间变化的曲线、每秒并发数、错误统计等可视化图表,比表格直观得多。
## 八、翻车现场与保命技巧
实践过程中遇到/预判的几个坑:
1. **下载超时**:JMeter 官方源国内极慢 → 换华为云镜像源
2. **中文乱码**:CSV 中文参数 → 文件编码指定 UTF-8
3. **内存溢出**:大压测前改 `jmeter.sh` 里的 `HEAP="-Xms1g -Xmx4g"`,按机器实际内存来
4. **结果文件撑爆硬盘**:`.jtl` 会记录每个样本,长稳测试记得只记错误样本或限制样本数
5. **监听器吃资源**:正式压测一律命令行模式,GUI 只用来调试脚本
## 九、总结
一次完整的 JMeter 压测闭环就是:**被测服务 → 参数化数据 → 带断言和思考时间的测试计划 → 冒烟验证 → 非GUI全量压测 → HTML报告分析**。
三条心得:
1. **脚本要像真人**:加思考时间、参数化、逻辑串联
2. **测试要像爬山**:5 → 100 → 更大,循序渐进
3. **分析要像侦探**:不只看平均值,重点看 90/95/99 分位线和错误率
以上完整脚本(`double11_test.jmx`)、被测服务源码(`mock_ecommerce_api.py`)、参数化数据(`users.csv`)和压测报告都在我的实践工程里,欢迎评论区交流。
**温馨提示**:压测前请务必在测试环境验证脚本,压测生产环境需提前知会相关人员。
---
*实践参考:华为云社区《JMeter压力测试,如何"温柔"地搞垮你的服务器?》,在此教程基础上完整落地了一遍流程。*
- 点赞
- 收藏
- 关注作者
评论(0)