十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

JMeter压测实战指南:从环境配置到分布式压测与结果分析

JMeter压测实战指南:从环境配置到分布式压测与结果分析 做性能测试这些年工具换了不少但 Apache JMeter 始终是我压箱底的那一个。原因很简单它开源、免费、跨平台脚本录制和编写都够灵活插件生态覆盖了 HTTP、HTTPS、JDBC、JMS、TCP 等主流协议小到给接口做一轮快速压测大到分布式集群发压都能用它完成。我自己带新人或者帮别的团队搭压测环境时几乎首选就是 JMeter。这篇指南把我平时带人讲的东西完整整理了一遍从装 JDK、解压 JMeter到写第一个压测脚本、读懂聚合报告里的指标再到上传文件、HTTPS、分布式压测和常见坑的排查。适合刚接触性能测试的测试开发、后端工程师也适合正在准备性能测试岗位面试、想快速在项目里落地压测方案的同学。看完可以直接照着做也能少踩几个我踩过的坑。1. 先想清楚JMeter 适合做什么不适合做什么1.1 核心能力与边界JMeter 本质是一个用纯 Java 实现的开源压力测试工具由 Apache 基金会维护。它最初只做 Web 请求的压力模拟后来慢慢扩展成支持 HTTP/HTTPS、FTP、JDBC 数据库查询、JMS、TCP、SMTP 等协议。实际项目里90% 的使用场景都集中在 HTTP 接口压测和 Web 应用并发模拟另外常见的还有 JDBC 压测数据库、JMS 压测消息队列。但要先说清楚边界。JMeter 不是全能的它主要解决客户端施加压力、记录响应数据这个问题。它本身不收集服务器侧的资源指标比如 CPU、内存、磁盘 IO、网络带宽这些要靠 PerfMon 插件或者用 Prometheus、Node Exporter 这类外部监控去补。它做 UI 层面的真实点击测试也不擅长虽然有 WebDriver Sampler 可以调用浏览器驱动但脚本编写成本高稳定性也不如专门的 UI 自动化工具。理解这个边界很重要。我遇到过不少新同事拿到 JMeter 就想把所有监控需求都塞进去结果录脚本花了大半天压测数据反而不准。正确的分工是JMeter 负责发压和数据采集服务端监控交给外部工具两者通过时间轴对齐才能定位瓶颈在应用、数据库还是网络。1.2 为什么不是 LoadRunner不是 Gatling也不是 Locust关于工具选型我做个简单的经验总结LoadRunner商业闭源工具功能强大但 License 昂贵录制脚本的传统模式对现在的接口测试反而显得笨重一般只有在政企项目强制要求时才用。Gatling用 Scala 写脚本性能强悍结果报告好看但对测试背景的同事很不友好你们组如果没有 Scala 开发经验上手会很痛苦。Locust用 Python 编写代码灵活度最高非常适合喜欢编程的团队但缺省的报告能力和 JMeter 相比差距不小而且脚本一旦写复杂维护成本也不低。JMeter 的优势在于图形界面加 XML 测试计划加上大量现成插件团队里不同背景的人都能快速上手。这就是为什么它长期占据开源压测工具的第一梯队社区问答多遇到问题搜一下基本都有答案。从实际对比看JMeter 的单机发压能力也不弱。在多线程模型下一台普通机器通常能模拟几千并发具体跟脚本复杂度和机器配置有关。如果还不够可以直接扩展成分布式压测主控调度、多个 Agent 同时发压。这个能力 LoadRunner 有但 JMeter 是免费的这部分我在第五部分展开。2. 环境准备先把 JDK 和 JMeter 配干净2.1 JDK 版本与 JMeter 版本的配对逻辑JMeter 是 Java 应用装它之前必须先有 JDK。不同 JMeter 版本对 Java 版本的要求不一样JMeter 5.5 及以前Java 8 就能跑JMeter 5.6 之后官方明确要求 Java 8 及以上但实际用 Java 11 或 17 更稳。我自己的习惯是装 Java 11 LTS配 JMeter 5.6.x这个组合踩坑最少。很多双击启动没反应的问题根源都在 JAVA_HOME 没配置好。先在命令行里验证java -version如果提示不是内部或外部命令说明 Java 没装或者没配环境变量。Windows 上还要单独看echo %JAVA_HOME%macOS/Linux 执行echo $JAVA_HOMEJAVA_HOME 应该指向 JDK 的安装目录而不是 JDK 里的 bin 目录。经常有人把 JAVA_HOME 指到C:\Program Files\Java\jdk-11.0.20\bin这会导致启动脚本拼接路径时出错。正确写法是只指到C:\Program Files\Java\jdk-11.0.20PATH 里才用到%JAVA_HOME%\bin。这个细节看着小能卡住一半新手。另外机器上如果有多个 Java 版本比如装了 Oracle JDK、OpenJDK可能还有 Android Studio 自带的 JBR这些都会干扰 JMeter 启动最好通过环境变量把 JAVA_HOME 锁到指定版本。改完后记得重新打开命令行窗口再验证一次。2.2 下载、解压与启动JMeter 的下载地址就是 Apache 官方站点 jmeter.apache.org打开 Downloads 页面选择 Binaries 那一栏下载 apache-jmeter-xxx.zip 或 .tgz解压就能用不需要安装程序。注意不要下载 Source 包那是源码包需要自己编译要下载 Binaries 包。解压后注意目录路径。Windows 下不要带空格和中文比如 D:\tools\jmeter避免后面脚本路径解析出各种奇怪问题。启动方式分平台Windows进入 bin 目录双击 jmeter.bat。macOS/Linux在终端执行 ./jmeter。第一次打开会看到 GUI 界面默认可能是英文在 Options Choose Language 里切换成简体中文即可。JMeter 的 GUI 主要用于编写和调试脚本正式压测时要改用命令行模式这一点后面反复强调不然很容易踩坑。如果在启动时看到 WARNING: Could not open/create prefs root key 之类的提示一般不影响使用可以忽略不必花时间折腾。真正需要重视的是启动后界面卡死或者内存报错那就要看下一节的基础配置了。2.3 三个最常用的基础配置JMeter 解压出来后有几个常用配置值得在真正压测前先改好。第一个是内存配置。bin 目录下的 jmeter.batWindows或 jmeter 脚本Linux/macOS头部有HEAP-Xms1g -Xmx1g默认只有 1G 堆内存。压测线程一多或者响应体比较大JMeter 自己会频繁 GCTPS 数据就不准了。我一般会改成HEAP-Xms4g -Xmx4g但别超过物理内存的一半否则 GUI 操作会卡。脚本里还有 NEW、SURVIVOR、TENURING 之类参数可以调优但普通压测场景堆内存给够就行。第二个是界面语言。在 jmeter.properties 里搜索 language去掉注释改成 languagezh_CN能让默认界面直接变中文。或者在 GUI 里菜单切换效果一样。第三个是日志级别。jmeter.properties 里有 log_level.jmeterINFO排查脚本时如果觉得日志不够细可以改成 DEBUG 看详细过程但跑正式压测前要改回 INFO否则大量日志会拖慢压测机。提示这些配置改完要重启 JMeter 才会生效。3. 第一次完整压测从测试计划到监听器3.1 线程组参数并发数、Ramp-Up 和循环次数在 GUI 左侧测试计划上右键添加 Thread Group 后界面里有三个关键参数。Number of Threads (users) 代表并发用户数。这个数字怎么定最合理的方式是从业务指标反推。假设线上高峰期半小时内总请求量是 18 万平均 QPS 就是 180000 除以 1800 秒等于 100。要验证系统是否扛得住翻倍流量压测目标可以定到 200 QPS并发线程数就设为能打到 200 QPS 的数值一般从 50、100、200、500 这样阶梯式往上试。Ramp-Up Period (seconds) 控制线程在多长时间内全部拉起来。我的习惯是 Ramp-Up 约等于并发数比如 200 并发就用 200 秒启动这样每秒新增 1 个线程服务器压力曲线是平滑的能明显看到系统在哪个并发点开始扛不住。如果设成 0JMeter 会立即把所有线程拉起相当于一瞬间做了次流量冲击这种模式适合验证限流不适合找性能拐点。Loop Count 决定每个线程重复执行多少次请求序列。做稳定性测试时勾选 Forever让脚本持续跑 10 分钟、30 分钟甚至 1 小时观察内存泄漏和连接池耗尽问题。如果只是看某个接口单次请求的性能Loop Count 设 1 就行。但要计算单用户 1 分钟能跑多少请求这种场景可以结合线程数和循环次数一起算比如 10 个线程、循环 60 次总请求数就是 600再除以分钟数就是吞吐量。实际项目里我一般这样组合冒烟测试1 个线程循环 1 次确认脚本通。基准测试50 并发Ramp-Up 50 秒循环 100跑出机器最优性能基线。负载测试100、200、500、1000 阶梯加压每档 5 分钟找出系统拐点。稳定性测试200 并发Ramp-Up 200 秒勾选 Forever跑 12 小时。3.2 HTTP 请求配置参数、Header 和鉴权线程组里添加 HTTP Request 后需要填写协议、服务器地址、端口、方法、路径这些基础信息。如果是本地测试环境服务器地址填 localhost端口填应用端口方法按接口文档选择 GET 或 POST。更麻烦的是接口带鉴权。很多业务接口要求请求头里带 Token这时在线程组上添加 HTTP Header Manager在里面添加 Authorization: Bearer xxxxx。问题的关键是 Token 从哪来。实际压测不能每次都注册新用户我的做法是用 setUp Thread Group初始化线程组先跑一次登录接口从响应里提取 Token存成全局属性业务线程组启动后通过 __property 读取这个 Token拼到 Header 里。这样所有线程共享一个有效会话更接近已登录用户的真实场景。另一种更接近真实的多用户场景是准备一批 Token 放进 CSV用 CSV Data Set Config 读取每个线程取一个不同的 Token。这种方式能避免所有请求共用一个 Token 带来的缓存命中偏差。我在项目里遇到过一次所有压测请求共用同一个 Token后端把所有重复请求都打到同一个用户的缓存上导致 TPS 虚高换了 CSV 多用户 Token 之后数据才真实反映接口性能。参数填写上GET 请求一般直接放 Parameters 区域POST 请求如果 Content-Type 是 application/json在 Body Data 区域放 JSON 字符串同时要在 Header Manager 里加 Content-Type: application/json。很多第一次写脚本的人在这里出错字段放了但 Header 没加服务端解析不到参数返回 415 或者 400。3.3 监听器如何搭配调试和压测是两套组合第一次写脚本时我建议先加 View Results Tree查看结果树来调试。它能看到每个请求的请求数据、响应头和响应体接口是否正常一目了然。但正式压测时千万别开着结果树跑因为结果树会把每个响应都缓存下来响应体一大内存分分钟爆掉。我自己就在这上面吃过亏1000 并发开着结果树跑16G 内存的机器直接卡死最后压测数据全作废。正式压测建议改用这些监听器Summary Report最通用能看 Samples、Average、Throughput、Error %压测完第一眼看这个。Aggregate Report多了 Median、90% Line、95% Line、Min/Max适合分析响应时间分布。Backend Listener把数据发送到 InfluxDB 加 Grafana适合长时间压测时实时看曲线这个后面有机会再单独写。如果团队已经搭好了 CI/CDJMeter 脚本可以集成进 Jenkins用命令行模式跑./jmeter -n -t test_plan.jmx -l result.jtl -e -o report_dir这个命令会生成一个 HTML 报告带各种图表发到群里让开发自己去看效率高很多。命令里 -n 表示非 GUI 模式-t 指定脚本-l 保存原始结果日志-e 生成 HTML 报告-o 指定报告输出目录。4. 让结果可信断言编写与性能指标解读4.1 常用断言与编写要领压测脚本如果不加断言接口返回 200 但响应内容其实是错误提示这种场景在压测时很容易让错误率虚低。断言就是用来解决这个问题的。最常用的是 Response Assertion响应断言。在 HTTP Sample 上右键添加断言配置响应文本、忽略状态、模式匹配规则即可。比如某个登录接口正常返回一串 JSON 且带 token 字段就加一个断言匹配模式写 token匹配规则选 Contains。模式匹配规则里有几个关键字容易混淆Contains响应文本包含指定字符串即可支持正则表达式。Substring也是包含关系但这里是纯文本查找不解析正则。Matches要求响应文本完整匹配该正则表达式整个响应文本必须等于表达式经常有人在这里翻车。Equals要求响应文本与给定值完全相等。JSON 接口推荐用 JSON Assertion。它可以直接写 JSONPath比如$.code然后选等于 200。写起来直观也省得被正则转义折腾。还有 Duration Assertion判断请求响应时间是否超过阈值比如超过 3000ms 就标记失败适合做超时校验。如果接口允许 200ms 内响应压测时大量请求超过 3s说明系统已经出现严重排队现象。我的经验是断言数量别贪多。每个请求加 3 到 4 个 JSON 断言JMeter 客户端 CPU 会明显上升压测机自己被拖累。一般在关键接口加 1 到 2 个断言确认状态码和关键字段即可更细的数据校验放到压测后的独立脚本里做。4.2 聚合报告先关注这五个指标压测完打开 Aggregate Report会看到一长串列。新手很容易看晕我只建议先关注这几个指标含义通常关注点Samples总请求数确认压测有没有按预期打出足够流量Average平均响应时间宏观性能但会被极端值拉偏只能作为辅助参考Median中位数响应时间50% 请求的响应时间比平均值更稳定90% Line / 95% Line百分位响应时间真实用户体验的近似值比平均值重要得多Error %请求错误率一般要求低于 0.1%支付/交易类要求更严Throughput每秒请求数TPS系统真实吞吐能力压测的核心指标常见误区是盯住 Average 不放。平均响应时间在数据分布不均衡时毫无意义如果有 1% 的请求耗时 5 秒剩下 99% 请求 200ms平均值也可能只有 248ms但用户真正体验到的却是长时间转圈。所以线上 SLA 一般用 P95/P99 来定义比如 P95 响应时间小于 1s而不是平均响应时间小于 1s。Throughput 的看点和并发数不一样。并发增加时TPS 会先上升再趋于平稳最后明显下降。如果压测时发现 TPS 不随线程数上升反而下降这就是系统瓶颈出现的信号应该停下来排查数据库连接池、线程池、慢 SQL而不是继续盲目加并发。4.3 结果分析中几个容易翻车的地方第一是压测机自身资源瓶颈。压测机 CPU 如果打满JMeter 只能慢慢发请求被测系统的真实性能根本测不出来。排查方法是压测时用 top 或任务管理器看 JMeter 进程CPU 使用率如果持续超过 80%要么加大内存、要么减少线程数或换分布式压测。第二是被测环境不够干净。压测前先把系统无关的后台任务、定时任务、日志清理停下来否则数据里混入太多噪声。有次我给一个 Java 服务压测TPS 始终在 300 上下波动后来发现是同一台机器上有另一个团队的定时任务每到整点抢 CPU把时间错开后数据立刻稳定了。第三是忽略网络影响。跨地域压测时网络延迟可能比应用处理时间还大这种数据不能用来评估系统性能。同机房、同一内网网段压测网络开销才能控制在合理范围。这也是为什么压测之前要先确认测试环境别拿生产网络当测试网络数据失真了都不知道原因在哪。5. 进阶实操与高频问题排查5.1 上传文件接口怎么压上传文件在 JMeter 里是很常见的需求配置并不复杂。HTTP Request 里把 Method 设为 POST勾选 Use multipart/form-data在 Files Upload 区域填文件路径、参数名和 MIME 类型。参数名要跟接口文档一致不是文件名。实际踩到的坑有两个路径问题Windows 上路径包含中文或空格上传经常报 400。建议先用简单的绝对路径验证比如 D:\test\test.pdf成功后再加上变量关联。multipart 格式问题如果接口既要普通字段又要文件普通字段放在 Parameters 里文件放在 Files Upload两者混在一起时经常出现字段丢失。还有一种动态文件名的场景比如每次上传的文件要求不重名可以通过 __time 和 __counter 函数生成动态文件名再把生成的参数拼到请求里。这种技巧在做批量导入接口压测时很实用。5.2 HTTPS 压测与录制脚本的证书问题压测 HTTPS 接口时最常见的问题是 SSL 握手失败。JMeter 作为客户端发起 HTTPS 请求默认会校验服务端证书链遇到自签名证书就直接拒绝。解决办法有两条路把服务端证书导入 JVM 的信任库。假设证书是 your.crt在 JAVA_HOME/lib/security/cacerts 目录下执行keytool -import -alias your_alias -keystore cacerts -file your.crt -storepass changeit导入后重启 JMeter再次请求就不会报 SSL 错误。注意 Java 9 之后证书库路径和旧版本略有差异先去确认自己的 JAVA_HOME。测试环境图省事可以跳过证书校验但生产环境千万别这么干等于把安全防线拆了。还有一个高频需求是用 JMeter 录制 HTTPS 脚本测试计划里添加 HTTP(S) Test Script Recorder配置端口默认 8888把系统浏览器代理指向 localhost:8888录制时浏览器会出现证书不受信任的提示需要先导出并安装 JMeter 自带的 ApacheJMeterTemporaryRootCA 证书。录完后脚本会生成很多资源请求建议清理掉图片、CSS、JS 等静态资源只保留业务接口否则压测的时候会把不必要的请求也打进去TPS 数据看着高实际没参考意义。5.3 分布式压测什么时候用、怎么做单机并发加到很高时压测机会先扛不住表现是 JMeter 所在进程 CPU 打满、TPS 上不去或者大量线程处于 waiting 状态。这时需要分布式压测主控Controller只负责调度和汇总数据多台负载机Agent分别执行脚本并发压测。基本步骤所有机器安装相同版本的 JMeter确保插件和 lib/ext 目录一致。负载机上执行 bin/jmeter-server 启动 Agent 服务。主控的 jmeter.properties 中设置remote_hostsagent_ip:port多个用逗号分隔。主控用命令行执行./jmeter -n -t test.jmx -l result.jtl -R 192.168.1.101:1099,192.168.1.102:1099-R 参数指定远程负载机列表也可以先在 GUI 的 Run Remote Start 里选择指定 Agent。这里最大的坑是脚本依赖如果脚本里用了 CSV 数据文件每台 Agent 上都必须有一份路径要一致如果脚本里调了自定义 jar 包所有 Agent 的 lib/ext 目录都得放一份否则 Agent 会报找不到类或变量无法解析排查起来很头疼。我记得有一次分布式压测三台 Agent 里有一台没同步 CSV结果那一台的请求全部用了默认值数据混进来根本没法分析。5.4 高频问题速查表下面这些是我在实际工作中被问得最多的问题整理成一张表方便直接查现象可能原因排查/解决方向双击 jmeter.bat 启动一闪而过JAVA_HOME 未配置或 Java 版本过低命令行 java -version修正 JAVA_HOMEGUI 卡顿压测数据异常开了结果树监听器内存不足关闭结果树调大 HEAP改用命令行模式中文响应乱码脚本/响应编码不是 UTF-8检查文件编码设置 HTTP Request 的 Content Encoding 为 UTF-8SSLHandshakeException自签名证书未导入信任库导入证书或使用 HTTP仅限测试环境上传文件接口报 400文件路径问题或 multipart 格式不对用绝对路径检查参数名与 MIME 类型远程 Agent 连不上RMI 端口未开放或 JMeter 版本不一致检查防火墙、server.rmi.port 配置统一 JMeter 版本TPS 很低但错误率也低请求共用 Token缓存命中虚高用 CSV 多 Token 模拟不同用户检查是否有缓存逻辑干扰这张表能覆盖大多数新手阶段的问题。真正的难点往往不在工具操作而在于怎么设计一个干净、可重复、变量受控的压测实验。最后分享一点这些年做压测的体会。JMeter 本身不难学真正常见的翻车点都在测试设计上并发数定得太随意、Token 共用导致缓存虚高、开了结果树拖垮压测机、跨网段压测干扰数据……这些问题工具不会提示你只能靠经验和复盘攒下来。如果你正在准备性能测试岗位的面试除了把 JMeter 操作练熟建议多想想这几个问题QPS 和并发数到底是什么关系P95 和平均值哪个更接近用户真实感受分布式压测时怎么判断压测机是否成了瓶颈把这些想明白了JMeter 对你来说就是顺手的东西而不是一开会就卡死的玩具。
返回列表