ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

JMeter 5.6.2 压测实战:从安装到分布式与CI集成

JMeter 5.6.2 压测实战:从安装到分布式与CI集成 简介Apache JMeter 5.6.2 是一款基于 Java 的开源压力测试工具面向性能测试工程师、开发人员及运维人员用于评估 Web 应用、数据库、FTP 等系统在高并发场景下的稳定性与响应速度。该资源为 rar 压缩包整体约 88.26MB解压后可直接运行 bin 目录下的启动脚本快速搭建测试环境。JMeter 以线程组模拟并发用户配合采样器、监听器、断言、定时器与配置元件构建完整测试计划支持 HTTP、JDBC、FTP 等多种协议并可通过插件扩展分布式测试与图形化能力。5.6.2 版本包含若干新特性、改进与错误修复适合从入门到进阶的测试人员参考使用。目前已有 328 人学习下载可作为性能测试学习与实战的实用工具包。1. JMeter 5.6.2 压测工具为什么你装的版本决定了后面踩多少坑很多人第一次接触 JMeter 5.6.2是因为接到一个「帮我压一下这个接口」的需求然后去搜 jmeter下载、jmeter安装教程装完打开界面加个线程组、加个 HTTP 请求、点运行看到聚合报告里出现数字就以为会用了。真正上生产压测时才发现QPS 上不去、报告看不懂、断言写不对、Linux 上跑着跑着内存爆了。JMeter 5.6.2 是 Apache 基金会维护的纯 Java 压测工具核心能力是把「并发请求 结果采集 报告输出」做成可配置的树形结构。它适合接口压测、简单业务场景并发验证、以及 CI 里做性能回归。不适合做浏览器端全链路渲染压测也不适合替代专业 APM 做线上全链路追踪。这一章先把版本、环境、适用边界讲清楚后面才敢谈参数和调优。2. 从零把 JMeter 5.6.2 跑起来JDK 选型、目录结构与最小压测脚本2.1 JDK 版本与安装方式的选择理由JMeter 5.6.2 官方要求 Java 8 及以上但实际用下来Java 8 和 Java 17 的差别在压测高并发时非常明显。Java 8 的 G1 在长时间压测下 Full GC 频率更高Java 17 的 ZGC 在几十 GB 堆上停顿更短。我一般推荐 Java 17 LTS除非你所在环境有强制 Java 8 的中间件依赖。安装方式上Windows 直接解压 apache-jmeter-5.6.2.zip 即可Linux 建议解压到 /opt 下并配好 PATH。不要用包管理器装旧版本因为插件生态和报告模板对版本敏感。# 下载二进制包以官方归档地址为例实际以官网为准 wget https://archive.apache.org/dist/jmeter/binaries/apache-jmeter-5.6.2.tgz tar -xzf apache-jmeter-5.6.2.tgz -C /opt # 配置环境变量 echo export JMETER_HOME/opt/apache-jmeter-5.6.2 ~/.bashrc echo export PATH$JMETER_HOME/bin:$PATH ~/.bashrc source ~/.bashrc jmeter -v逻辑说明tar -xzf解压后JMETER_HOME指向根目录bin/jmeter是启动脚本。jmeter -v会打印版本和 Java 版本如果这里报NoClassDefFoundError基本是 JDK 没配好或 JAVA_HOME 指向了 JRE 而不是 JDK。参数说明-v只输出版本不启动 GUILinux 上不要直接jmeter启动 GUI会因为没有 X11 报错压测用-n非 GUI 模式。2.2 目录结构里哪些文件必须改解压后重点看三个位置bin/jmeter.properties、bin/user.properties、lib/ext。jmeter.properties是全局默认配置user.properties是个人覆盖配置升级时只保留 user.properties 即可。lib/ext放插件 jar比如做 HTML 报告汉化模板或自定义函数时用。常见做法是把jmeter.properties里jmeter.save.saveservice.output_format改成 csvjmeter.save.saveservice.thread_counts改成 true这样 jtl 文件里会带线程数后面生成报告时能画出并发曲线。# user.properties 里覆盖不要直接改 jmeter.properties jmeter.save.saveservice.output_formatcsv jmeter.save.saveservice.thread_countstrue jmeter.save.saveservice.response_datafalse jmeter.save.saveservice.samplerDatafalse逻辑说明output_formatcsv比 xml 更省 IO压测时写 jtl 的线程不会成为瓶颈。thread_countstrue让每行结果带当前活跃线程数报告里的「Active Threads Over Time」才有数据。response_datafalse和samplerDatafalse关掉响应体和请求体记录否则大响应会把磁盘写满。参数说明如果压测中需要看具体响应内容排查问题临时把response_data打开但只在小并发下用高并发下这个开关是磁盘杀手。2.3 最小可运行压测脚本的创建步骤GUI 只用来建脚本和调试真正压测用命令行。建脚本步骤新建测试计划勾选「独立运行每个线程组」。添加线程组线程数 10Ramp-Up 5 秒循环 10 次。添加 HTTP 请求默认值填服务器 IP 和端口。添加 HTTP 请求路径填/api/login方法 POSTBody Data 填 JSON。添加响应断言断言响应码 200。添加聚合报告和查看结果树调试时用压测时删掉查看结果树。# 非 GUI 模式运行 jmeter -n -t login_test.jmx -l result.jtl -e -o report_output逻辑说明-n非 GUI-t指定 jmx 脚本-l指定结果文件-e -o表示压测结束后自动生成 HTML 报告到指定目录。注意-o指向的目录必须不存在或为空否则会报错。参数说明-l的 jtl 文件在压测过程中持续写入如果中途停止已写入部分仍可用于生成报告。-e -o生成报告会消耗额外 CPU如果压测机本身压力大可以压测完再单独用jmeter -g result.jtl -o report_output生成。3. 接口压测脚本进阶参数化、断言与动态 QPS 控制3.1 CSV 参数化与动态验证码处理压测登录接口时固定用户名密码只能测出缓存命中后的性能真实场景需要不同用户。用 CSV Data Set Config 读取用户列表配合__Random函数生成随机手机号。username,password user001,pass001 user002,pass002 user003,pass003!-- 在线程组下添加 CSV Data Set Config -- CSVDataSet guiclassTestBeanGUI testclassCSVDataSet testname用户参数 stringProp namefilename/data/users.csv/stringProp stringProp namevariableNamesusername,password/stringProp stringProp namedelimiter,/stringProp stringProp namerecycletrue/stringProp stringProp namestopThreadfalse/stringProp /CSVDataSet逻辑说明recycletrue表示文件读完后从头再读适合长时间压测。stopThreadfalse表示文件读完不停止线程而是继续用最后一组数据。如果要做「每个用户只登录一次」的场景把recycle设为 false 并配合stopThreadtrue。参数说明filename用绝对路径相对路径在不同工作目录下会找不到。variableNames要和 CSV 表头一致否则引用时取不到值。动态验证码是压测登录接口最常见的拦路虎。常见做法是在压测环境关闭验证码或者用固定验证码。如果必须动态获取用 BeanShell 断言或 JSR223 断言从上一个响应里提取。// JSR223 断言从登录响应中提取 token import org.json.JSONObject; String response prev.getResponseDataAsString(); JSONObject json new JSONObject(response); String token json.getString(token); vars.put(token, token);逻辑说明prev是 JMeter 内置变量代表上一个采样器结果。getResponseDataAsString()拿到响应体解析 JSON 后把 token 存入 JMeter 变量后续请求用${token}引用。参数说明JSR223 断言要选 Groovy 语言不要用 BeanShellGroovy 性能更好且线程安全。如果响应不是标准 JSON用正则提取器更稳。3.2 响应断言与 Beanshell 断言的取舍响应断言只能判断响应码、响应文本包含某字符串。Beanshell 断言可以写逻辑比如判断业务码、判断响应时间、判断字段是否存在。// Beanshell 断言业务码为 0 且响应时间小于 500ms String response new String(ResponseData); if (!response.contains(\code\:0)) { Failure true; FailureMessage 业务码非0: response; } if (prev.getTime() 500) { Failure true; FailureMessage 响应时间超过500ms; }逻辑说明ResponseData是字节数组需要转字符串。Failure设为 true 表示断言失败FailureMessage会显示在结果里。prev.getTime()是上一个请求的耗时单位毫秒。参数说明Beanshell 断言在高并发下性能较差因为每次都要编译脚本。如果断言逻辑复杂且并发高改用 JSR223 断言 Groovy并勾选「缓存编译脚本」。3.3 用 While 控制器和定时器动态调整 QPS固定线程数压测只能测出某个并发下的表现真实需求往往是「逐步加压看拐点」。用 Ultimate Thread Group 插件可以做阶梯加压但不想装插件时用 While 控制器 Constant Throughput Timer 也能实现动态 QPS。!-- While 控制器条件为 ${__javaScript(${__threadNum} 100)} -- WhileController guiclassWhileControllerGui testclassWhileController testname动态加压 stringProp nameWhileController.condition${__javaScript(${__threadNum} lt; 100)}/stringProp /WhileController逻辑说明__threadNum返回当前线程编号从 1 开始。While 控制器在条件为 true 时循环执行子元件。配合 Constant Throughput Timer 设置目标吞吐量可以模拟逐步增加并发。参数说明Constant Throughput Timer 的「Target throughput」单位是每分钟比如要 600 QPS 就填 36000。注意这个定时器是「尽力而为」实际 QPS 受限于服务器响应时间和压测机性能。提示动态调整 QPS 时不要只看聚合报告里的平均值要看 90% 和 99% 分位。平均值会被少量快请求拉低掩盖长尾问题。4. 压测执行与报告Linux 命令行、HTML 报告汉化与结果解读4.1 Linux 非 GUI 压测的完整命令与后台运行生产压测基本都在 Linux 上跑因为 Windows 的 TCP 端口回收慢高并发下容易报Address already in use。# 后台运行并记录日志 nohup jmeter -n -t /data/scripts/order_test.jmx \ -l /data/results/order_$(date %Y%m%d_%H%M%S).jtl \ -j /data/logs/jmeter.log \ -e -o /data/reports/order_report_$(date %Y%m%d_%H%M%S) \ /dev/null 21 逻辑说明nohup让进程在终端关闭后继续运行放后台。-j指定 JMeter 运行日志排查启动失败时看这个文件。-l和-o都带时间戳避免多次压测覆盖。参数说明如果压测时间很长jtl 文件会很大可以加-Jjmeter.save.saveservice.thread_countstrue确保线程数被记录。-e -o在压测结束后生成报告如果压测中途 kill 掉报告不会生成需要用-g单独生成。4.2 HTML 报告汉化模板的替换方法JMeter 默认生成的 HTML 报告是英文的给非技术同事看时不太友好。汉化方法是替换bin/report-template下的模板文件。# 备份原模板 mv /opt/apache-jmeter-5.6.2/bin/report-template /opt/apache-jmeter-5.6.2/bin/report-template-bak # 放入汉化模板从社区获取的 report-template 目录 cp -r /data/report-template-zh /opt/apache-jmeter-5.6.2/bin/report-template逻辑说明报告模板是 freemarker 格式汉化主要是改content目录下的.ftl文件里的静态文案。替换后重新生成报告即可生效。参数说明不同 JMeter 版本的模板结构可能不同5.6.2 的模板和 5.5 有差异不要混用。替换前务必备份否则升级时会丢。4.3 聚合报告里哪些数字必须看指标含义关注点Average平均响应时间容易被少量快请求拉低参考价值有限Median中位数50% 请求的响应时间比平均值稳90% Line90% 请求的响应时间核心指标反映大多数用户体验99% Line99% 请求的响应时间长尾指标反映最差体验Min/Max最小/最大响应时间Max 异常大时排查超时请求Error %错误率超过 0.1% 就要查原因Throughput吞吐量单位是请求数/秒或分钟看单位Received KB/sec网络接收速率判断是否达到网卡瓶颈逻辑说明压测报告不是看一个数就下结论。90% Line 和 Error% 要一起看如果 90% Line 很低但 Error% 很高说明大量请求快速失败可能是连接被拒。如果 90% Line 很高但 Error% 为 0说明服务器处理慢但没崩。参数说明Throughput 的单位取决于报告配置默认是每分钟。如果看到 60000 这种数字先确认单位别误以为 QPS 六万。5. 避坑与排查压测中常见的 5 个翻车现场5.1 现象压测机 CPU 跑满QPS 上不去原因JMeter 本身是 Java 应用GUI 模式、大量断言、查看结果树都会消耗压测机 CPU。很多人把压测机和被测服务部署在同一台机器上资源互相抢占。解决压测机独立部署用非 GUI 模式关掉查看结果树和「保存响应数据」。如果单台压测机不够用分布式压测master 只负责调度slave 负责发压。5.2 现象Linux 上运行报java.net.NoRouteToHostException或连接超时原因JMeter 默认走系统代理设置如果环境变量里有http_proxyJMeter 会把请求发到代理而不是目标服务。解决在jmeter.properties里确认http.proxyHost和http.proxyPort为空或者启动时加-H和-P参数显式指定。检查~/.bashrc里有没有代理相关环境变量。5.3 现象CSV 参数化时所有线程用了同一行数据原因CSV Data Set Config 默认是「所有线程共享」模式每个线程读到的行取决于读取顺序不是每个线程独立一行。解决把「Sharing mode」改成「Current thread」每个线程独立读取。如果要做「每个线程用不同用户」用__threadNum拼接用户名或者用「All threads」配合__counter函数。5.4 现象Beanshell 断言在高并发下报OutOfMemoryError原因Beanshell 每次执行都编译脚本产生大量临时对象堆内存被撑爆。解决改用 JSR223 断言 Groovy并勾选「Cache compiled script if available」。如果必须用 Beanshell把堆内存调大但治标不治本。5.5 现象生成的 HTML 报告里「Active Threads Over Time」是空的原因jmeter.save.saveservice.thread_counts默认为 falsejtl 文件里没有记录线程数。解决在user.properties里加上jmeter.save.saveservice.thread_countstrue重新压测。已经生成的 jtl 文件无法补录只能重跑。注意压测前先确认 jtl 文件里有没有线程数字段否则报告生成后才发现缺数据只能重来。6. 进阶技巧用分布式压测和 CI 集成把 JMeter 5.6.2 用成性能回归工具单机压测到几万 QPS 后压测机本身会成为瓶颈。分布式压测的思路是一台 master 调度多台 slave 发压结果汇总到 master。配置步骤所有 slave 安装相同版本的 JMeter 和 JDK。slave 上启动jmeter-server默认端口 1099。master 的jmeter.properties里remote_hosts填 slave 的 IP:1099。命令行加-R指定 slave 列表或-r使用配置里的所有 slave。# master 上执行分布式压测 jmeter -n -t order_test.jmx -R 192.168.1.101:1099,192.168.1.102:1099 \ -l result_dist.jtl -e -o report_dist逻辑说明-R显式指定 slave适合临时加机器。-r读取remote_hosts配置适合固定集群。结果文件汇总在 master 上slave 只负责发压和回传结果。参数说明分布式压测要求 master 和 slave 的 JMeter 版本、插件、JDK 版本一致否则会报序列化错误。slave 上不需要放 jmx 脚本master 会自动分发。CI 集成方面把 JMeter 命令写进 Jenkinsfile 或 GitLab CI 的 script 段每次构建后生成 HTML 报告并归档。关键是要设置性能基线比如 90% Line 超过 800ms 或 Error% 超过 0.5% 就标记构建失败。// Jenkinsfile 片段 stage(Performance Test) { steps { sh jmeter -n -t order_test.jmx -l result.jtl -e -o report perfReport sourceDataFiles: result.jtl, errorFailedThreshold: 0.5, errorUnstableThreshold: 0.1 } }逻辑说明perfReport是 Jenkins Performance Plugin 提供的步骤errorFailedThreshold是错误率失败阈值errorUnstableThreshold是不稳定阈值。超过阈值时构建状态会变黄或变红。参数说明阈值要根据业务容忍度设不要照搬。核心支付接口错误率阈值应该比查询接口更严。基线数据要跑多次取稳定值不要用单次结果当基线。我自己踩过最深的坑是第一次做分布式压测时slave 的 JDK 版本和 master 不一致结果压测跑了 10 分钟master 上只收到 3 条结果排查了半天才发现是序列化不兼容。从那以后我养成了一个习惯压测前先跑一个 10 线程 10 秒的冒烟脚本确认 master 能收到所有 slave 的结果再上正式脚本。希望帮到你。本文还有配套的精品资源点击获取
返回列表