ARTICLE DETAIL

资讯详情

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

JMeter性能压测实战:从安装配置到报告分析全攻略

JMeter性能压测实战:从安装配置到报告分析全攻略 JMeter这工具说实话第一次打开的时候我是有点懵的。满屏的英文菜单什么线程组、监听器、取样器第一反应是这玩意儿是给专业测试用的吧。但后来因为要接手一套微服务迁移后的高并发验证工作硬着头皮啃了两周才发现这东西的底子其实不复杂。你把它的逻辑理顺了它就是你手里一把特别顺手的压力测试刀。这篇笔记我把我从下载安装到压测出报告、再到查报错的全过程整理出来里面很多坑都是我亲手踩过的希望能帮你少走点弯路。这玩意儿能干啥简单说就是接口测试、自动化回归、以及最核心的性能压测。它模拟一堆用户同时点你的系统把你的接口打到冒烟看你的服务器和数据库到底能扛多少并发。适合测试工程师、开发自测、运维做容量评估以及像我这样被临时抓壮丁去验证环境的半路出家人。不废话了直接开整。1. 装对环境和版本选型千万别在第一步栽跟头1.1 下载渠道与版本选择JMeter是Apache基金会的开源项目下载地址认准Apache官网。别去第三方下载站。我之前图方便在某个软件站下了一个整合版结果里面捆绑了一堆全家桶还带了个旧版本的JRE差点把我电脑搞崩。官网下载页找到Download Releases选版本号和对应系统的压缩包就行。Windows就下ZIPmacOS/Linux也建议用TAR.GZ不需要安装解压即用。版本选择这块我个人的建议是不追新但也不要太旧。JMeter 5.4、5.5、5.6这些版本目前都还活跃界面和功能差异不大。但要注意它和JDK的对应关系——这个东西放在1.2专门说因为十个人有八个人在这里翻车。1.2 JDK版本匹配版本号对应表JMeter本质是一个Java程序你得装了JDK才能跑。最典型的报错就是双击jmeter.bat屏幕一闪而过或者干脆提示找不到java命令。JDK版本匹配原则JMeter版本JDK最低版本建议JDK版本JMeter 5.5JDK 8JDK 8 / 11JMeter 5.6.xJDK 8JDK 11 / 17JMeter 5.7如有JDK 11JDK 17我本机用的是JDK 1.8也就是JDK 8搭配JMeter 5.5稳如老狗。如果你需要用到一些新特性或者新插件可能得升到JDK 11。检查JDK版本的方法命令行输入java -version看到类似openjdk version 1.8.0_xxx的就是8看到11.0.x就是11。另外一个隐藏坑你电脑装了JDK但JMeter启动还是报错。这时候看环境变量JAVA_HOME配没有。JMeter优先找JAVA_HOME找不到才找系统PATH里的java。提示JAVA_HOME路径里不要带空格更不要指到C:\Program Files\Java\jdk...这种带空格的路径下。遇到玄学启动问题先检查这个。1.3 启动方式和目录结构解压后进入目录Windows用户双击bin\jmeter.batmacOS/Linux用户给bin\jmeter.sh加执行权限后运行./jmeter.sh。打开之后会有一个黑底白字的控制台窗口这个窗口千万不能关。关了就相当于把JMeter的引擎给关了。控制台主要是打印日志真正的图形界面是后面弹出来的那个。至于JMeter目录里你真正需要关心的就三个地方bin/启动脚本、配置文件jmeter.properties、user.properties都在这里面。lib/扩展依赖。你要连数据库、连MQTT相关jar包就往这里丢。logs/运行日志目录。压测出问题第一步来这里看jmeter.log。1.4 最容易踩的三个环境坑直接说结论都是我确认过的问题第一中文路径问题。JMeter的解压路径、后续脚本保存路径尽量不要出现中文和空格。我之前把脚本放桌面上结果压测过程中察看结果树有时能出结果有时报文件写入失败排查半天是路径编码的锅。第二界面空白或字体怪异。Windows下如果JMeter界面按钮挤在一起或者失踪大概率是JDK版本太高导致的不兼容。换回JDK 8或11问题马上消失。JDK 17之后某些版本jmeter.bat默认参数会有点小毛病不是不能用但没必要跟自己过不去。第三内存设置。默认内存压测大并发时会报OutOfMemoryError。建议打开bin\jmeter.batWindows或jmeterLinux脚本找到HEAP那一行改成-Xms1g -Xmx4g -XX:MaxMetaspaceSize512m。4G堆内存对本机压测基本够用要是压测机内存大可以再往上调。2. 接口测试最小闭环线程组、HTTP请求、断言与关联环境好了之后别急着压测先把接口测试玩明白因为压测脚本本质上就是一堆接口请求的集合。2.1 从线程组到HTTP请求完成第一次调用打开JMeter界面你能看到四个主要部分测试计划、工作台、左侧树状导航、右侧配置区。第一步建立线程组。右键测试计划 → 添加 → 线程用户 → 线程组。线程组就是定义有多少用户、怎么跑、跑多久的地方。调试接口的时候线程数设1循环次数设1别一上来就100并发那是压测时才做的事。第二步加HTTP请求。右键线程组 → 添加 → 取样器 → HTTP请求。这就是接口调用本体了。填写方式协议http或https服务器名称或IPapi.example.com端口号默认80或443如果你调的是8080端口的服务必须填上方法GET或POST下拉选择路径/api/v1/users注意路径以/开头请求体POST的话切到请求体标签写JSON填完添加一个察看结果树线程组 → 添加 → 监听器 → 察看结果树点工具栏上的绿色三角运行。左侧能看到请求列表点开就能看到请求报文和响应报文。测接口最核心的就是看响应码、响应体、断言结果。2.2 RESTful参数怎么写路径参数与查询参数jmeter restful 参数怎么写这个问题拆开看就是三种情况。一是路径参数比如/api/orders/{id}要请求ID为10001的订单路径直接写/api/orders/10001即可没有额外的参数配置就是这么简单。二是查询参数比如/api/orders?statuspaidpage1。在HTTP请求采样器下方有个参数标签页一行行加参数名填status值填paid再一行参数名page值1。JMeter会自动拼在URL后面。这样填的好处是参数可以后续做参数化变量名直接写在值那一栏比硬写在路径里好维护。三是POST的JSON体参数比如登录接口{ username: admin, password: 123456 }在请求体标签页直接粘贴这段JSON注意方法必须是POST。不需要在参数标签里重复填否则会拼成?usernameadminpassword123456后端收不到JSON体。经验现在的新项目大部分是JSON交互。如果碰到老项目是form表单提交别用请求体写JSON要去参数标签里填键值对Content-Type会自动变成application/x-www-form-urlencoded。2.3 关联登录token如何传给下一个接口接口测试80%的精力都花在怎么把上一个接口的返回值塞进下一个接口的请求里。这在JMeter里叫关联它不是JMeter自动帮你做的需要你用提取器手动处理。最常见的场景先调登录接口拿返回的token后续所有接口的请求头都会带着这个token。具体操作分两步第一步添加JSON提取器。右键登录的HTTP请求 → 添加 → 后置处理器 → JSON提取器。变量名填login_tokenJSON路径表达式假如登录接口返回{data:{token:abc123}}那这里填$.data.token匹配数字填1取第一个匹配值第二步在下一个接口引用变量。在业务接口的HTTP请求里添加HTTP信息头管理器线程组 → 添加 → 配置元件 → HTTP信息头管理器然后加一行名称Authorization值Bearer ${login_token}这样跑的每个接口都会带着登录返回的动态token。运行的时候变量名如果没取到值JMeter会原样输出${login_token}字符串一眼就能看出来是不是提取失败了。还有一种是正则提取器适用场景更广。服务器返回的响应头或响应体里有动态值比如一个sessionIdxxxxxxxx用正则sessionId(.*?)就能抓出来。做法跟JSON提取器如出一辙只是正则表达式字段需要写正则。2.4 断言响应码200不代表接口对接口通了、能返回数据了下一个问题就是返回的数据对不对响应码200只是服务器没崩不代表业务逻辑通过。比如你查订单服务器返回了{code:500,msg:订单不存在}HTTP状态码依然是200但业务上是失败的。所以断言的重点是业务层的校验。JMeter里最常用的断言有两种响应断言右键HTTP请求 → 添加 → 断言 → 响应断言。响应文本选中默认就是模式匹配规则选包含测试模式加一行code: 200或者status: success这样响应体里只要包含这些字段就通过。如果接口大量返回JSON格式推荐用JSON断言它不用写正则直接填$.code和期望值200语义更清晰。真实项目中一个请求往往挂多个断言——一个校验HTTP层响应一个校验业务code必要时再加一个响应时间断言比如要求响应时间小于500ms。3. 参数化的三种姿势CSV、数据库与函数做压测的时候100个用户全部用同一个账号登录这不叫压力测试这叫打同一个账号的并发。真实场景里每个用户都有自己的登录凭证和业务数据所以我们需要参数化让每个线程用不同的数据。3.1 CSV Data Set Config从文件读数据文件参数化最常用适合账号密码、商品ID这种静态数据。准备CSV文件比如users.csvusername,password user01,pass123 user02,pass456 user03,pass789添加CSV Data Set Config右键线程组 → 添加 → 配置元件 → CSV Data Set Config。关键配置文件名填写CSV文件的绝对路径变量名称填username,password跟CSV表头一一对应逗号隔开分隔符,视文件实际而定是否允许带引号False默认遇到文件结束符True表示继续从文件开头循环。压测时通常选True保证每个线程都有数据可用线程共享模式All threads默认然后在HTTP请求的用户名和密码字段直接填${username}和${password}。有个大坑CSV文件不要用Notepad记事本直接保存UTF-8必出乱码。用VS Code或Notepad另存为UTF-8 without BOM格式JMeter读起来才正常。3.2 JDBC Request参数化从数据库直接捞数据有时候测试数据太多导CSV不现实或者你想测这条数据在库里存在、状态正确的接口逻辑。这时候就需要直接连数据库动态从库里捞数据。第一步放驱动jar包。MySQL数据库把mysql-connector-java-x.x.x.jar扔到JMeter的lib目录下重启JMeter。这个jar可以从Maven中央仓库下载别找第三方站。第二步配置JDBC Connection Configuration。右键测试计划 → 添加 → 配置元件 → JDBC Connection Configuration。Variable Name for created pool填db_pool后面引用要用Database URL填jdbc:mysql://localhost:3306/test_db?useUnicodetruecharacterEncodingutf8JDBC Driver class选com.mysql.jdbc.Driver新版选com.mysql.cj.jdbc.DriverUsername / Password数据库账号密码第三步JDBC Request取样器。右键线程组 → 添加 → 取样器 → JDBC Request。Variable Name of Pool declared in Configuration Element填db_poolSQL Query写查询语句比如SELECT id FROM orders WHERE statusPAID LIMIT 1;Variable Names填order_id查询结果要存成的变量名Result variable name如果有多个查询结果填一个存储所有结果集的变量名第四步取查询结果作为下一个接口参数。这是热词里提到的将jdbc request查询出的数据作为下一个接口的参数。这里分两种情况单行单列查询结果只有一个值那${order_id}直接就是那个值。多行数据查询出多条记录JDBC Request的结果变量命名规则是order_id_1、order_id_2、order_id_3...对应每一行。如果希望取随机一行可以用${__V(order_id_${__Random(1,10,)})}这种嵌套函数的方式。多个字段的话比如查id, name两个字段变量名填id,name取到的值就是${id_1}、${name_1}。3.3 函数助手随机数、计数器与时间戳CSV和JDBC解决的是从外部读数据函数助手解决的是临场生成数据。点击菜单选项 → 函数助手对话框或者直接用快捷键CtrlShiftF1。几个很常用的__Random随机数。比如生成1到9999填${__Random(1,9999,)}。__counter计数器每个线程调一次自动加1。压测场景下生成唯一的用户名、手机号特别方便。__time取当前时间戳。填${__time(yyyy-MM-dd HH:mm:ss,)}拿到格式化时间或${__time(,)}拿到原始毫秒时间戳。比如要生成唯一手机号可以这样写139${__time(,)}取当前13位毫秒时间戳的后9位拼出来就是一台一亿多的设备号几乎不会重。4. 录制HTTPS脚本代理配置、证书安装与清洗说实话手工写脚本适合接口数量少的场景。万一系统有几十个接口一个个写HTTP请求能把人写疯。这时候用JMeter的录制功能最省力。4.1 HTTP代理服务器的配置过程录制的基本原理是JMeter在本地起一个代理端口浏览器的流量都走这个端口JMeter把流量拦截下来自动转成脚本里的HTTP请求。操作步骤右键测试计划 → 添加 → 非测试元件 → HTTP代理服务器端口默认8080保持默认。如果被占用就换8081目标控制器选测试计划 线程组录制出来的请求放在哪个线程组里分组建议选每个组放入一个新的控制器这样JMeter会自动按请求的域名和逻辑分组点击启动按钮然后浏览器设置代理以Chrome为例设置 → 高级 → 系统 → 打开您计算机的代理设置Windows下在局域网设置里填地址127.0.0.1端口8080。设置好之后在浏览器里正常操作你要录制的业务流程JMeter树形列表里就会一个个蹦出HTTP请求。操作完毕把浏览器代理关掉点JMeter的停止按钮。4.2 HTTPS证书为什么录制的请求全是安全连接失败HTTP的录制没啥问题HTTPS就会报证书错误浏览器访问https://xxx时提示您的连接不是私密连接。原因很简单HTTPS需要证书验证JMeter作为中间代理它签发的证书不在浏览器信任列表里浏览器就不认它。解决办法分两步第一步生成JMeter证书。JMeter启动起来之后首次运行代理时会在它的bin目录下生成一个ApacheJMeterTemporaryRootCA.crt文件这就是JMeter的CA根证书。如果这个文件没生成确认一下代理是否启动过。第二步把证书导入到浏览器信任区。Windows下双击这个.crt文件 → 安装证书 → 选择本地计算机 → 将所有证书都放入下列存储 → 浏览 → 选择受信任的根证书颁发机构 → 完成。macOS下双击crt文件 → 钥匙串访问 → 找到该证书 → 设为始终信任。证书导入后重启浏览器再走一遍代理HTTPS请求就能正常录制了。录制完成后建议把信任的证书删掉避免之后访问其他HTTPS站点走代理时被中间人截获这只是个安全习惯问题。注意录制完一定要关掉浏览器代理设置并停掉JMeter代理进程。我之前录完忘了关结果整个系统上网全走代理其他网站全访问不了排查了半天还以为断网了。4.3 录制后的脚本清洗从能跑到跑得对录制产生的脚本直接压测一定会出问题。原因是录制脚本抓的是实际请求里面包含大量的静态资源请求图片、CSS、JS、无意义的cookie、以及本不该硬编码的动态参数。我录制完一个流程通常做三件事第一删静态资源。可以用HTTP请求默认值配合正则过滤或者在代理服务器配置里加过滤在HTTP代理服务器的排除模式里加一行.*\.(js|css|png|jpg|gif|ico)(\?.*)?重新录制就直接不录这些了。如果已经录上了手动删除即可。这些静态资源的请求对性能测试没有意义只会污染数据和接口统计。第二参数化动态值。录制下来的请求里凡是跟登录时间随机ID临时的token相关的都要挑出来替换成变量。比如你录了一个创建订单的请求订单号是固定的那并发压测时每笔订单都是同一个号服务端很可能会有幂等校验导致第二笔请求全失败。第三加断言和监听器。录制脚本本身没有断言跑完根本不知道结果对不对。在关键接口上补上断言压测的时候才有个准心。5. BeanShell断言与Cookie管理进阶实战5.1 BeanShell断言你值得拥有响应断言和JSON断言能满足80%的校验需求但遇到需要复杂逻辑判断的场景就不够用了。比如你要校验返回值是否等于数据库里的某个值或者需要根据返回内容做不同的分支处理——这时候就是你上BeanShell的地方。先说明一点JMeter 3.1开始官方推荐用JSR223 Groovy替代BeanShell因为Groovy性能更好、语法更现代。但热词里jmeter beanshell断言搜得人太多说明网上教程还是老一套而且说实话BeanShell和JSR223 Groovy的用法几乎一样你会一个就会另一个。这里我用BeanShell讲思路抛砖引玉。右键HTTP请求 → 添加 → 断言 → BeanShell断言。BeanShell里你可以拿到的关键变量ResponseData响应体字节数组prevSampleResult对象prev.getResponseCodeAsString()拿响应码prev.getResponseDataAsString()拿响应体字符串varsJMeter变量上下文vars.get(varName)读变量vars.put(varName, value)写变量实际断言脚本String resp prev.getResponseDataAsString(); if (resp.contains(\code\: 200)) { Failure false; } else { Failure true; FailureMessage 响应中未找到业务成功码, 响应内容: resp; }Failure true代表断言失败FailureMessage是失败原因。这一套逻辑其实是JUnit断言的翻版学会了之后就能做很多文档型断言做不到的事比如解析JSON里某个嵌套字段之后再做字符串匹配。但我要给你提个醒BeanShell断言的性能较差压测时每个请求都会执行这个脚本高并发下会成为性能瓶颈。压测场景下强烈建议用JSR223 断言并在脚本语言里选groovy逻辑一样但跑得快得多。开发调试用BeanShell方便压测执行前务必切到Groovy。5.2 Cookie管理与会话保持很多系统靠Cookie维持登录状态特别是老一点的Java Web项目。JMeter压测时每个线程默认是独立的它不会自动保存上一个请求返回的Cookie除非你加一个HTTP Cookie管理器。右键线程组 → 添加 → 配置元件 → HTTP Cookie管理器。这个元件什么都不用配置放在那JMeter就会自动收集每次响应里的Set-Cookie并在后续请求自动带上。等效于浏览器里的cookie存储。有两个注意点第一手动添加Cookie。有些接口需要你先从某个请求里拿Cookie值然后塞到后续请求里但HTTP Cookie管理器只认Set-Cookie响应头。如果Cookie是前端JS算出来的或者是从响应体里自定义的那就得手动加在Cookie管理器里点添加填写名称和值值可以用变量引用比如${generated_cookie}。第二跨线程组共享Cookie。多线程组场景比如线程组A负责登录并产生Cookie线程组B要带着这个Cookie去做业务操作。Cookie管理器默认只在线程组内生效跨组就失效了。解决办法是把login接口提取到setUp线程组所有线程组之前执行用__setProperty函数把Cookie值设为JMeter全局属性然后在业务线程组的Cookie管理器里用${__property(cookie_value)}引用。5.3 防伪标记__RequestVerificationToken 未提供这问题一看就是ASP.NET MVC项目。搜索jmeter 测试 mvc3项目提示__requestverificationtoken 未提供必要的防伪标记大概率是你在压测一个加了防CSRF攻击的网站的POST接口。这个错误的机制是MVC的[ValidateAntiForgeryToken]特性要求POST请求里必须带一个隐藏字段__RequestVerificationToken而这个字段的值和当前会话的Cookie是绑定的。浏览器正常操作时前端会自动在表单里生成这个字段并随请求提交。但JMeter是裸发起请求的没有经过页面渲染自然就没有这个字段。解决思路跟前面讲token关联如出一辙第一步先发一个GET请求到表单所在页面获取响应里的__RequestVerificationToken值通常在一个隐藏Input里用一个正则提取器就能抓出来同时HTTP Cookie管理器会自动保存这次GET响应里的验证Cookie。第二步在POST请求里把提取到的token值加到请求参数中参数名叫__RequestVerificationToken值就是那个变量。这里有个关键点这个token跟Cookie是一一对应的第一次GET时的Cookie必须和POST时的Cookie一致所以Cookie管理器别乱清放对位置就好。5.4 文件上传Multipart请求怎么构造jmeter上传文件也是一个高频需求。做法分三步在线程组下添加HTTP请求方法选POST勾选Use multipart/form-data for POST在文件上传那一栏文件名称填本地文件的绝对路径参数名称填服务端接口要求的字段名通常是fileMIME类型按需填图片填image/png不放心填application/octet-stream这样发出的请求就是标准的multipart文件上传格式。如果要同时提交一个描述字段比如remark测试图片直接在参数标签里加一个键值对JMeter会自动把它作为multipart里的普通表单字段一起发出去。要注意的是jmeter 文件已经存在这个报错。如果你用参数化方式压测上传有个文件名称你写的是相对路径而脚本文件被挪到别处跑JMeter找不到那个文件就会报这个错。解决方法是把文件路径写成绝对路径或者用user.dir变量动态拼接。还有一个场景是CSV数据文件被JMeter当成测试文件上传了检查一下文件上传那一栏的路径别填错。6. 压测环节从线程组设计到非GUI模式与报告6.1 线程组设计并发数、Ramp-Up和循环次数调试跑通了进入压测环节。这时候线程组的设计就是核心中的核心。五个关键参数线程数模拟多少个并发用户。Ramp-Up Period秒在多长时间内把线程全部启动。循环次数每个线程执行几次脚本。调度器配置设置压测总时长、延迟启动时间。Same user on each iteration勾选项每次迭代是否复用同一个用户。这里有一个重要的公式每秒请求量QPS ≈ 线程数 × 循环次数 ÷ 单次请求总耗时。比如100个线程单次请求耗时200ms那每秒大约能打出100 × 5 500个请求。第一次压测建议区间设置参数建议值说明线程数50 ~ 200先小后大阶梯加压别上来就5000并发Ramp-Up10 ~ 60秒让用户慢慢入场模拟真实场景也避免瞬时冲击循环次数100 ~ 1000或勾选永远配合调度器持续压测N分钟调度器时长视场景而定压测至少跑5分钟以上数据才有统计意义压测不是只跑一轮就行。理性的做法是50并发跑10分钟看基线然后100并发、200并发、500并发逐级往上加每轮记录各项指标找到拐点。所谓拐点就是响应时间开始急剧上升、吞吐量不再线性增长的临界并发数。6.2 非GUI模式运行命令行压测命令用JMeter图形界面压测到500并发以上JMeter自己就卡成了PPT严重时还会因为界面渲染消耗CPU导致压测数据失真。所以压测的硬性要求是非GUI模式。命令行基础命令jmeter -n -t test_plan.jmx -l result.jtl -e -o report_dir参数含义-n非GUI模式-t指定测试计划文件.jmx-l指定结果文件.jtl保存原始采样数据-e -o测试结束后自动生成HTML报告到指定目录实际执行例子jmeter -n -t order_pressure_test.jmx -l ./result/result_050.jtl -e -o ./result/html_050压测机上跑建议把所有监听器都删掉或禁用尤其是察看结果树和图形结果它们会严重影响压测性能只在调试阶段用。6.3 HTML报告看懂哪些指标-e -o生成的是个index.html文件打开后有四个板块APDEX应用性能指数业内标准通常要求大于0.9反映的是用户体验满意度。响应时间图表重点关注P50、P90、P95、P99。P99是最慢的1%用户感受的延迟压测时先看P99是否达标再考虑平均值。平均值这个值很容易被极端值带偏。吞吐量Throughput每秒完成的事务数也就是QPS。错误率错误请求数÷总请求数。压测允许有错误请求但错误率超过0.1%就要停下来分析原因不能心存侥幸。最终看指标是否符合预期需要跟业务方确定SLA服务等级协议比如P95响应时间 500ms错误率 0.1%QPS ≥ 2000。没有SLA的压测报告出来也没法判断好坏。6.4 压测中常见报错java.io.IOException: error writing to server这是热词里提到的一个高频压测错误输出在JMeter命令行或控制台ERROR - jmeter.protocol.http.sampler.HTTPHTTPAbstractImpl: java.io.IOException: error writing to server这个报错的意思是JMeter作为客户端往服务器写数据发请求时出错了底层网络连接中断。导致这个错误的原因主要是以下几种第一种服务端主动断开了连接。并发一大服务端连接池打满、后端超时、JDBC连接池耗尽都可能导致服务端直接断开连接。你去查服务端日志多半能看到connection reset、500之类的记录。这是最常见的原因。第二种JMeter端到服务端链路问题。比如压测机和服务器之间有LB负载均衡或防火墙把长时间空闲或者超时的连接给掐了。看错误后缀如果有Connection reset by peer基本就是网络链路问题。第三种JMeter本身的连接问题。压测机发请求太猛本机文件描述符或端口用完了。Windows上常见因为Windows默认可用的临时端口只有一万多个高并发下会被耗尽。Linux下检查ulimit -n限制。排查顺序建议是先查服务端日志和控制台报错再查中间链路Nginx/LB/防火墙最后查压测机自身资源。比如我可以给你串一个完整的排查链路压测200并发时大量error writing to server→ 打开服务器Nginx日志看到connect() failed (111: Connection refused) while connecting to upstream→ 去查后端服务的并发连接数和线程数 → 发现Tomcat最大线程数只有200而压测线程数是300大量请求排不上队Nginx直接返回拒绝 → 调整Tomcat的maxThreads后重启再压错误消失。这类排查关键时间点日志里都有线索慢不要紧关键是别看到这个报错就慌。7. 真实案例k8s微服务迁移后如何用JMeter做高并发验证这部分拿来收尾。前面讲的全是JMeter的操作细节很多人学完都会问一个问题这一整套到底用在哪里我这里说一个真实的典型场景单节点k8s上的微服务环境整套迁移到了云上ECS迁移完需要压测验证云上的承载能力。这正是JMeter的当家用途。7.1 为什么迁移后需要压测微服务从自建机房或本地k8s迁到云上CPU型号变了、内网延迟变了、磁盘IOPS变了各项性能都可能发生偏移。云上配置看着高实际吞吐不见得比本地强。我之前处理过一套类似问题IAM和网关的链路上报错率在本地压测时是0.05%迁移后涨到了1.2%。后来排查发现是云上ECS的带宽限制比本地机房小云磁盘的IOPS也有上限大量写日志时数据库写入延迟翻了几倍。所以用了云资源不等于性能自动提升必须用真实流量压一遍。7.2 压测前的环境校验和配套准备执行压测前有四个准备工作第一评估压测机的部署位置。压测机建议跟目标服务在同一VPC内网避免公网带宽波动导致测试数据失真。压测结果里响应时间一旦出现规律性的毛刺很可能就是网络抖动而不是业务问题。第二准备测试数据。接口压测最怕没数据。订单查询接口要压库里得先造一批不同状态的订单数据。登录接口要压得按账号数量准备一批有效用户和Token。这个我在前面参数化部分讲了用JDBC准备数据锁库的方式效率最高。第三监控配套。JMeter只能看到客户端视角的指标服务端的CPU、内存、GC、数据库慢查询得配合云监控、自建Prometheus/Grafana来看。压测过程中一旦发现JMeter这边吞吐下降立刻去服务端监控面板对时间点看服务端的表现。第四脚本一定要先小规模验证。用10并发跑1分钟确认压测指标曲线平稳、无报错再进入正式压测。这一步省下的调试时间远大于花费的时间。7.3 压测步骤、结果判读和问题定位一个可复用的压测流程可以这样定部署JMeter到压测机非GUI模式先跑50并发5分钟确认环境依次跑100并发、200并发、500并发、1000并发每轮10分钟每轮记录QPS、P95、P99、错误率在服务端监控面板标记每轮的时间范围方便复盘数据汇总成表格分析拐点比如某次压测结果整理如下并发数QPSP95响应时间P99响应时间错误率100850145ms230ms0.00%2001500230ms420ms0.00%5002300580ms1120ms0.03%100024501500ms3200ms0.25%从这组数据就能看出拐点在500并发附近从500到1000并发翻倍但QPS几乎没涨P99却涨了快3倍错误率也开始抬头。这说明系统瓶颈已经暴露了继续加压没有意义这时候去看服务端瓶颈在哪里比拼命加并发数重要得多。实际定位问题的时候我习惯按这个顺序去查Nginx错误日志 → 应用容器CPU/内存 → 数据库慢查询 → Redis超时 → 应用GC日志。90%以上的性能瓶颈最终都落在数据库慢查询和GC上这两块排查优先级最高。另外一个细节压测结束之后要把压测产生的脏数据清理掉。很多团队压完懒得清数据结果测试库里堆了几万条无效订单下一轮压测数据都是畸形的测试结论根本不靠谱。8. 插件扩展MQTT插件与更多可能性最后一个话题插件。JMeter官方原生只支持HTTP、HTTPS、FTP、JDBC、TCP等协议但物联网场景测MQTT、消息队列场景测Kafka就要靠插件了。8.1 插件管理器安装手动下载插件jar包往lib/ext里扔也能用但极其不方便版本匹配也容易出问题。推荐直接用Plugins Manager。从JMeter插件官网下载plugins-manager.jar放到JMeter的lib/ext目录下重启JMeter工具栏上多出一个Plugins Manager图标三个拼图块的样子点开后就能搜索并安装插件了。它会自动帮你处理依赖关系比手动下包省心得多。8.2 MQTT插件IoT场景的压测MQTT场景——比方说压测一个车联网平台的上下线、消息上报通常需要专门的压测工具但JMeter有了插件之后也能客串一把。搜索热词里jmeter下载mqtt插件的比例不低。在Plugins Manager里搜MQTT会看到类似MQTT Protocol Support的插件安装后重启。使用路径线程组 → 添加 → 取样器 → MQTT连接采样器先建立连接再添加MQTT发布采样器模拟设备上报数据如果需要客户端订阅也有MQTT订阅采样器。这类插件的参数一般包括Broker地址tcp://broker.example.com:1883、ClientID建议参数化否则所有压测线程共用同一个ClientID会互相踢下线、Topic名称、QoS级别、Payload内容。ClientID这里是个大坑压测时一定要加${__threadNum}后缀或用UUID保证每个线程唯一否则Topic里全是连接踢来踢去的报错。除了MQTTPlugins Manager里还有自定义线程组插件比如Ultimate Thread Group可以精确控制线程分布形状比如前60秒每5秒加50线程维持120秒最后30秒每5秒减50线程。这种阶梯式压测比单线程组更贴近真实流量特征。我自己压测大并发时都是用这个线程组控制力比原生线程组强得多。写在最后我从第一次打开JMeter一脸懵到现在能独立完成一整套压测流程整个过程踩的坑比想象中多。如果你刚开始学我的建议是先拿一个最简单的GET接口把线程组-Http请求-查看结果树-断言这个最小闭环跑通再逐步叠加参数化、关联和压测模式。别上来就看那些长篇大论的功能清单纯属浪费时间。碰到报错不要慌记住一个原则JMeter的报错90%都指向配置不对而不是工具坏了。照着下面的口诀排查一轮大部分问题都能解决请求错了看路径和参数响应错了看断言和编码连接断了看并发和服务端日志变量不替换看提取器和作用域。等你能把压测跑顺、能把报告里的QPS、P99、错误率讲清楚再去做性能优化这时候JMeter才算真正成了你手里的工具而不是眼里的一堆菜单。
返回列表