1. 为什么选择Apifox进行并发测试
在Java后端开发中,性能测试是确保系统稳定性的关键环节。传统上我们可能会选择JMeter这样的专业工具,但对于日常开发中的快速验证,Apifox提供了更轻量级的解决方案。我最近在黑马点评项目的优惠券秒杀功能测试中,就采用了Apifox进行200并发线程的压测,这里分享下具体操作和踩过的坑。
Apifox的优势在于:
- 与Postman类似的友好界面,学习成本低
- 内置自动化测试功能,无需额外配置
- 可以直接复用项目已有的接口定义
- 断言功能完善,能快速验证结果
提示:虽然Apifox比JMeter轻量,但对于复杂的性能测试场景,还是建议使用专业的JMeter或LoadRunner。
2. 测试环境准备
2.1 接口基本信息
我们需要测试的是优惠券秒杀接口:
- 请求方式:POST
- 请求路径:
http://localhost:8081/voucher-order/seckill/11 - 路径参数:11表示优惠券ID
- 请求头:需要携带用户token
这个接口实现了基本的秒杀功能,但还没有添加乐观锁等并发控制机制,正是我们测试的重点。
2.2 Token获取与配置
由于黑马点评项目采用了基于Token的认证机制,所有请求都需要携带有效的用户凭证。获取Token的方式:
- 通过Chrome开发者工具(F12)
- 切换到Network标签页
- 在项目中任意操作触发API请求
- 查看请求头中的
authorization字段值
在Apifox中配置全局Token:
- 进入"环境管理"
- 添加全局变量如
token - 将获取到的Token值填入
- 在接口请求头中添加
Authorization: Bearer {{token}}
注意:Token通常有有效期,测试时确保使用未过期的Token。我曾因为使用过期Token导致所有请求被拦截,浪费了大量排查时间。
3. 并发测试配置
3.1 创建测试用例
- 在Apifox中新建测试用例
- 添加我们准备好的秒杀接口
- 设置并发数为200(模拟200个用户同时抢购)
- 设置循环次数为1(每个用户只请求一次)
3.2 关键参数说明
- 并发数:模拟的真实用户数量,根据服务器配置合理设置
- 超时时间:建议设置为5000ms,避免因网络波动导致误判
- 思考时间:设置为0,模拟真实秒杀场景的瞬时高并发
3.3 预期结果验证
由于我们测试的优惠券库存只有100个,理论上最多只能有100个请求成功。但初次测试时发现200个请求全部返回200状态码,这显然不符合预期。
原因分析:
- 接口没有做库存校验
- 或者库存校验存在并发问题
- Apifox默认只检查HTTP状态码,不验证业务逻辑
4. 添加业务断言
4.1 断言配置
为了准确验证业务逻辑,我们需要在后置操作中添加断言:
- 在接口的"Tests"标签页中添加脚本
- 验证响应体中的业务状态码
- 示例断言代码:
javascript复制pm.test("Check stock limit", function() {
var jsonData = pm.response.json();
pm.expect(jsonData.code).to.be.oneOf([200, 500]);
if(jsonData.code === 500) {
pm.expect(jsonData.msg).to.include("库存不足");
}
});
4.2 断言逻辑说明
- 成功情况:code=200
- 失败情况:code=500且msg包含"库存不足"
- 其他情况:标记为测试失败
4.3 再次测试结果
添加断言后重新测试,可以看到:
- 总请求数:200
- 成功请求:约100个(具体取决于并发控制实现)
- 失败请求:约100个,返回库存不足提示
这样我们就准确验证了在高并发下系统的实际表现。
5. 常见问题与解决方案
5.1 所有请求都被拦截
现象:所有请求返回401状态码
原因:
- Token未正确配置
- Token已过期
- 请求头中Authorization格式错误
解决方案:
- 检查全局变量中的Token值
- 确保请求头格式为
Authorization: Bearer your_token - 重新获取有效Token
5.2 测试结果不符合预期
现象:库存100的商品,200并发全部成功
原因:
- 缺少业务断言,只验证了HTTP状态码
- 后端未实现库存校验
- 库存校验存在并发问题
解决方案:
- 添加完善的业务断言
- 检查后端库存扣减逻辑
- 考虑添加乐观锁机制
5.3 测试结果不稳定
现象:相同测试参数下,每次成功请求数波动大
原因:
- 服务器资源不足
- 数据库连接池限制
- 网络波动
解决方案:
- 增加服务器配置
- 调整数据库连接池参数
- 多次测试取平均值
6. 性能优化建议
通过这次测试,我们发现系统在高并发下存在超卖问题。根据经验,可以考虑以下优化方案:
- 乐观锁实现:
java复制// 示例乐观锁实现
boolean success = seckillVoucherService.update()
.setSql("stock = stock - 1")
.eq("voucher_id", voucherId)
.gt("stock", 0) // 添加库存判断
.update();
- Redis预减库存:
- 将库存信息缓存到Redis
- 先在Redis中原子性减库存
- 减成功后再进行数据库操作
- 消息队列削峰:
- 将秒杀请求放入RabbitMQ等消息队列
- 后端服务按处理能力消费
- 接口限流:
- 使用Guava RateLimiter或Redis实现限流
- 防止系统被突发流量击垮
在实际项目中,我通常会先加乐观锁解决最基本的并发问题,然后再逐步引入Redis和消息队列等高级方案。这样既能快速解决问题,又能保证系统稳定性。