news 2026/5/9 9:20:55

自动化测试(六) API性能测试-JMeter脚本化与Gatling代码化双方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
自动化测试(六) API性能测试-JMeter脚本化与Gatling代码化双方案

API性能测试:JMeter脚本化与Gatling代码化双方案

前面咱们搞定了功能测试,但接口能跑通不代表能扛住流量。今天聊性能测试——JMeter和Gatling两个主流工具,什么时候用哪个?怎么设计压测场景?


一、性能测试不是"把并发调大就行"

很多新手做性能测试,上来就设置"1000并发跑10分钟",然后看TPS高不高。这其实是个误区。

性能测试的三种类型

类型目的怎么测
负载测试系统在正常负载下表现如何逐步加压到预期峰值,观察指标
压力测试系统的极限在哪持续加压直到系统崩溃,找瓶颈
稳定性测试长时间运行会不会出问题保持中等负载跑几小时/几天,看内存泄漏

关键指标解读

┌─────────────────────────────────────────────────────────┐ │ 用户请求 ──> 响应时间(Latency) <── 服务端处理 │ │ ├── 网络传输时间 │ │ ├── 服务端处理时间 │ │ └── 数据库/缓存查询时间 │ │ │ │ TPS(每秒事务数)= 完成的请求数 / 时间 │ │ 并发数 = 同时在线的用户/连接数 │ │ 吞吐量 = 单位时间处理的数据量(MB/s) │ │ │ │ 错误率 = 失败请求 / 总请求 │ │ P50/P95/P99 = 50%/95%/99%的请求响应时间 │ └─────────────────────────────────────────────────────────┘

重点关注P99而不是平均响应时间。平均数容易被少数快请求拉低,P99告诉你"最慢的那1%用户"体验如何。


二、JMeter:老牌但够用的GUI工具

快速上手

下载解压后,直接运行bin/jmeter.bat(Windows)或bin/jmeter.sh(Mac/Linux)。

一个简单的压测脚本

Step 1:添加线程组(模拟用户)

右键测试计划 → 添加 → 线程(用户)→ 线程组 线程数:100 ← 并发用户数 Ramp-Up:10秒 ← 10秒内启动100个用户 循环次数:10 ← 每个用户执行10次

Step 2:添加HTTP请求

右键线程组 → 添加 → 取样器 → HTTP请求 协议:https 服务器名称:api.example.com 端口:443 方法:GET 路径:/api/products

Step 3:添加监听器(看结果)

右键线程组 → 添加 → 监听器 → 聚合报告 右键线程组 → 添加 → 监听器 → 查看结果树

Step 4:运行

点绿色三角按钮,等跑完看聚合报告:

Label #Samples Average Median 90%Line 95%Line 99%Line Min Max Error% Throughput HTTP请求 1000 156 120 280 350 500 50 800 0.00% 450.2/sec

JMeter的进阶配置

参数化:不同用户不同数据
右键线程组 → 添加 → 配置元件 → CSV数据文件设置 文件名:users.csv 变量名:username,password

users.csv内容:

user001,pass001 user002,pass002 user003,pass003

HTTP请求中引用:

路径:/api/login 参数: username: ${username} password: ${password}
断言:验证响应
右键HTTP请求 → 添加 → 断言 → 响应断言 测试字段:响应文本 模式匹配规则:包含 测试模式:"success":true
思考时间:模拟真实用户停顿
右键线程组 → 添加 → 定时器 → 高斯随机定时器 偏差:1000ms ← 平均停顿1秒 固定延迟偏移:500ms

JMeter的痛点

痛点说明
GUI模式资源消耗大压测时别用GUI,用命令行模式
脚本难版本控制.jmx是XML,diff看不懂
分布式配置麻烦主从节点要配RMI,防火墙端口要开
复杂逻辑难实现想做个条件分支?写BeanShell吧,痛苦

命令行模式(生产环境必须用):

# 非GUI模式运行jmeter-n-tapi-test.jmx-lresult.jtl-e-oreport/# -n: 非GUI模式# -t: 测试脚本# -l: 结果日志# -e: 生成报告# -o: 报告输出目录

三、Gatling:代码化压测的新选择

Gatling用Scala DSL写压测脚本,虽然要学点Scala语法,但回报巨大。

引入依赖

<dependency><groupId>io.gatling.highcharts</groupId><artifactId>gatling-charts-highcharts</artifactId><version>3.9.5</version><scope>test</scope></dependency><plugin><groupId>io.gatling</groupId><artifactId>gatling-maven-plugin</artifactId><version>4.6.0</version></plugin>

第一个Gatling脚本

// src/test/scala/com/example/ApiSimulation.scalapackagecom.exampleimportio.gatling.core.Predef._importio.gatling.http.Predef._importscala.concurrent.duration._classApiSimulationextendsSimulation{// HTTP协议配置valhttpProtocol=http.baseUrl("https://api.example.com").acceptHeader("application/json").contentTypeHeader("application/json")// 场景定义valscn=scenario("查询商品场景").exec(http("查询商品列表").get("/api/products").queryParam("page","1").queryParam("size","20").check(status.is(200)).check(jsonPath("$.total").exists)).pause(1,3)// 思考时间:1-3秒随机停顿.exec(http("查询商品详情").get("/api/products/${productId}")// 从session中提取变量.check(status.is(200)))// 注入负载配置setUp(scn.inject(rampUsers(100).during(10.seconds),// 10秒内启动100用户constantUsersPerSec(50).during(60.seconds)// 然后保持50/s的速率跑60秒)).protocols(httpProtocol)}

运行:

mvn gatling:test-Dgatling.simulationClass=com.example.ApiSimulation

Gatling的DSL有多爽

复杂场景编排
valbrowse=scenario("浏览购买流程")// 1. 登录.exec(http("登录").post("/api/auth/login").body(StringBody("""{"username":"${username}","password":"${password}"}""")).check(jsonPath("$.token").saveAs("authToken"))// 提取token存到session).pause(2)// 2. 浏览商品(从CSV feeder读取商品ID).feed(csv("products.csv").random).exec(http("查看商品").get("/api/products/${productId}").header("Authorization","Bearer ${authToken}").check(jsonPath("$.stock").saveAs("stock"))).pause(1,5)// 3. 条件判断:有库存才下单.doIf(session=>session("stock").as[Int]>0){exec(http("创建订单").post("/api/orders").header("Authorization","Bearer ${authToken}").body(StringBody("""{"productId":"${productId}","quantity":1}""")).check(status.is(201)))}
多种负载模型
setUp(// 模型1:逐步加压(找拐点)scn.inject(nothingFor(5.seconds),atOnceUsers(10),rampUsers(100).during(30.seconds),rampUsers(500).during(60.seconds),rampUsers(1000).during(120.seconds)),// 模型2:脉冲负载(模拟秒杀)spikeScenario.inject(rampUsers(10000).during(10.seconds),nothingFor(30.seconds),rampUsers(10000).during(10.seconds)),// 模型3:稳定性测试stabilityScenario.inject(constantUsersPerSec(100).during(2.hours))).protocols(httpProtocol)
丰富的断言
// 全局断言setUp(scn.inject(...)).protocols(httpProtocol).assertions(global.responseTime.max.lt(1000),// 最大响应时间 < 1sglobal.successfulRequests.percent.gt(99.0),// 成功率 > 99%global.requestsPerSec.gt(100),// TPS > 100details("创建订单").responseTime.percentile(95).lt(500)// 下单P95 < 500ms)

Gatling的报告

运行完后自动生成HTML报告,长这样:

target/gatling/apisimulation-20240101120000/ ├── index.html # 总览 ├── js/ # 图表JS └── req_*.html # 每个请求的详细统计

报告包含:

  • 响应时间分布图(直方图 + 百分位曲线)
  • 每秒请求数/响应数趋势
  • 活跃用户数变化
  • 错误统计和堆栈

四、JMeter vs Gatling:怎么选?

维度JMeterGatling
学习曲线低(GUI点点点)中(要学Scala DSL)
脚本维护难(XML难diff)易(代码可版本控制)
复杂场景难(BeanShell痛苦)易(代码灵活)
资源消耗较高较低(Netty异步IO)
报告美观一般优秀(自带炫酷图表)
团队协作测试人员为主开发人员顺手
生态插件丰富(社区插件多)较少但够用

我的建议:

  • 快速验证/测试团队用→ JMeter
  • 持续集成/开发团队用→ Gatling
  • 复杂业务场景→ Gatling(代码比GUI灵活太多)

五、性能测试的"坑"与最佳实践

坑1:在本地跑压测

你的笔记本能模拟1000并发?别闹了。网络带宽、CPU、内存都是瓶颈。

正确做法:用专门的压测机器,或者云厂商的压测服务(阿里云PTS、AWS Load Testing等)。

坑2:不预热直接压

JVM要预热(JIT编译),连接池要初始化,缓存要填充。一上来就猛压,结果不准。

正确做法:

// Gatling中加个预热阶段scn.inject(rampUsers(100).during(60.seconds),// 先慢慢预热1分钟constantUsersPerSec(1000).during(300.seconds)// 再正式压测5分钟)

坑3:只压一个接口

真实场景是多个接口混合调用,比例不同。

正确做法:

// 模拟真实用户行为比例setUp(// 80%用户只浏览browseOnly.inject(rampUsers(800).during(60.seconds)),// 15%用户浏览+加购物车browseAndCart.inject(rampUsers(150).during(60.seconds)),// 5%用户完整购买流程fullPurchase.inject(rampUsers(50).during(60.seconds))).protocols(httpProtocol)

坑4:不看服务端指标

客户端TPS高,但服务端CPU 100%、内存OOM、GC频繁,这不算"通过"。

正确做法:压测时同时监控:

  • 服务端CPU/内存/磁盘IO
  • 数据库连接池使用率、慢查询
  • Redis命中率、连接数
  • JVM GC频率和耗时
  • 网络带宽

坑5:没有基线和对比

“这次压测TPS是500”——然后呢?上次是多少?优化后提升了多少?

正确做法:每次压测结果存档,建立性能基线,优化前后对比。


六、Spring Boot + Gatling 集成示例

// 在Spring Boot测试里启动Gatling压测@SpringBootTest(webEnvironment=SpringBootTest.WebEnvironment.RANDOM_PORT)classPerformanceTest{@LocalServerPortprivateintport;@TestvoidrunGatlingSimulation()throwsException{// 设置系统属性,让Gatling连上随机端口System.setProperty("gatling.http.baseUrl","http://localhost:"+port);// 运行GatlingGatlingPropertiesBuilderprops=newGatlingPropertiesBuilder().simulationClass("com.example.ApiSimulation").resultsDirectory("target/gatling-results");Gatling.fromMap(props.build(),List.of());}}

七、小结

今天咱们聊了性能测试的方方面面:

主题要点
性能测试类型负载测试、压力测试、稳定性测试,目的不同
关键指标关注P99、错误率、吞吐量,别只看平均数
JMeterGUI易上手,适合快速验证和测试团队
Gatling代码化DSL,适合复杂场景和CI集成
常见坑本地压测、不预热、单接口压测、不看服务端指标、无基线

一句话总结:JMeter是"瑞士军刀",Gatling是"精密仪器"。日常快速验证用JMeter,持续性能测试和复杂场景用Gatling。


你们性能测试用JMeter还是Gatling?遇到过什么坑?欢迎聊聊。


版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/9 9:17:40

【YOLO目标检测全栈实战专栏】04 模型压缩与量化:把YOLOv8塞进边缘设备的“瘦身秘籍”

还记得上周在客户现场,我盯着那块Jetson Nano开发板直冒冷汗。客户要求用YOLOv8做实时口罩检测,我自信满满地部署了训练好的模型——结果呢? FPS只有3.2,画面卡得像PPT。客户总监站在旁边,眉头越皱越紧,我恨不得把模型塞进微波炉里“加热”一下让它跑快点。 那一刻我意…

作者头像 李华
网站建设 2026/5/9 9:17:35

哔哩下载姬DownKyi:从零开始轻松下载B站8K超高清视频的完整教程

哔哩下载姬DownKyi&#xff1a;从零开始轻松下载B站8K超高清视频的完整教程 【免费下载链接】downkyi 哔哩下载姬downkyi&#xff0c;哔哩哔哩网站视频下载工具&#xff0c;支持批量下载&#xff0c;支持8K、HDR、杜比视界&#xff0c;提供工具箱&#xff08;音视频提取、去水印…

作者头像 李华
网站建设 2026/5/9 9:16:47

构建实时字幕翻译系统:PotPlayer插件深度解析

构建实时字幕翻译系统&#xff1a;PotPlayer插件深度解析 【免费下载链接】PotPlayer_Subtitle_Translate_Baidu PotPlayer 字幕在线翻译插件 - 百度平台 项目地址: https://gitcode.com/gh_mirrors/po/PotPlayer_Subtitle_Translate_Baidu PotPlayer_Subtitle_Translat…

作者头像 李华
网站建设 2026/5/9 9:16:46

ncmdumpGUI:网易云音乐NCM格式转换的终极解决方案

ncmdumpGUI&#xff1a;网易云音乐NCM格式转换的终极解决方案 【免费下载链接】ncmdumpGUI C#版本网易云音乐ncm文件格式转换&#xff0c;Windows图形界面版本 项目地址: https://gitcode.com/gh_mirrors/nc/ncmdumpGUI 你是否曾经在网易云音乐下载了心爱的歌曲&#x…

作者头像 李华
网站建设 2026/5/9 9:16:00

GraphQL与AI智能体融合实践:利用gqlpt实现自然语言操作API

1. 项目概述&#xff1a;当GraphQL遇上AI代理最近在折腾一个挺有意思的开源项目&#xff0c;叫rocket-connect/gqlpt。简单来说&#xff0c;它干了一件挺“缝合”但又很实用的事儿&#xff1a;让AI大语言模型&#xff08;比如GPT-4、Claude这些&#xff09;能够直接、安全地操作…

作者头像 李华