ARTICLE DETAIL

资讯详情

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

JMeter分布式压测进阶:从Master-Slave架构原理到常见报错排查指南

JMeter分布式压测进阶:从Master-Slave架构原理到常见报错排查指南 1. 为什么要做分布式压测单机瓶颈与现实需求做性能测试的人都绕不开JMeter但只要压测规模稍微往上走单机跑压测这件事儿就越来越不靠谱。先说清楚一个根本问题你在一台电脑上开10万个线程做并发能不能真的压出10万的并发量答案大概率是不能。因为JMeter本身是Java写的每个线程在JVM里都有对应的栈空间和内存占用线程数上去了GC开销、上下文切换、socket连接数都会把本机资源吃掉一大截。更关键的是压测机本身如果已经CPU跑满、内存告急那压出来的延迟数据、吞吐量曲线就完全失真了看起来像是在压被测系统实际上压的是你自己那台电脑。这就是分布式压测存在的最核心动机把压测请求的产生压力分散到多台机器上让每台压测机只承担一部分并发整体把压力抬上去同时对被测系统进行真实的、大规模的压力模拟。还有一个很多人没意识到的场景就是当你需要模拟来自不同地域、不同网段的真实用户流量时分布式压测在拓扑上也更贴近现实至少在来源IP、网络路径上能模拟得更有说服力。这篇文章我会把JMeter分布式压测从原理、环境准备、核心配置、脚本设计到真实踩坑后的排查方法全部串一遍。适合两类人看一类是刚开始搭分布式压测、照着文档也配不明白的新手另一类是已经能跑通但经常遇到“Error writing to server”这类问题不知道该从哪里下手的测试开发。看完之后你可以照着思路直接把整套环境弄起来并能独立排查大多数报错。需要提前说明的是不同JMeter版本的配置细节略有差异尤其是JMeter 4.0前后SSL处理方式变化很大文章里我会把版本差异单独拿出来讲避免跟着老教程在新版本上踩坑。2. 分布式压测的核心逻辑与架构设计2.1 Master-Slave机制到底是怎么工作的JMeter分布式压测采用经典的Master-Slave结构。简单说你准备一台控制机Master若干台执行机Slave/Agent。Master负责管理测试脚本、分发任务、汇总结果Slave负责真正发送请求。请求流程大致是Master把本地写好的.jmx测试计划推送给每一个SlaveSlave各自启动JVM按照脚本里的线程数和循环次数开始向目标服务器发请求。执行过程中每个Slave会自己收集结果数据然后通过RMI协议把结果回传给MasterMaster再做聚合展示。这里有个容易误解的地方Master在分布式压测中并不参与实际发送请求它只做分发和汇总。所以别再问“控制机要不要配高性能CPU”这种问题了只要别太拉胯就行真正干活的是Slave。另一个关键点是分布式压测中的线程数是按每台Slave独立生效的。比如你在脚本里配置了线程数为1000那么有3台Slave时实际产生的并发总量是3×10003000而不是所有Slave一共只有1000。这个乘法关系一开始就要算清楚否则你很容易把真实压测压力估低。2.2 版本演进对分布式配置的直接影响JMeter的分布式功能虽然从很早就有了但配置方式经历过几次重要变化直接影响你现在照着网上教程操作能不能成功。最大的分水岭是JMeter 4.0JMeter 4.0之前RMI通信默认走动态端口需要手动在jmeter.properties里设置server.rmi.port并且还要处理RMI的SSL配置很麻烦。很多老教程里会教你改JMeter启动脚本添加-Djava.rmi.server.hostname之类的参数其实就是那个年代的产物。JMeter 4.0开始官方默认启用了RMI的SSL认证并且提供了create_rmi_keystore.bat或者.sh脚本一键生成rmi_keystore.jks密钥文件。这样Master和Slave之间的通信变得安全很多但同时也多出一道配置门槛——如果你忽略了证书生成和分发这个环节大概率会卡在“连接被拒绝”或者RMI握手失败上。JMeter 5.x及后续版本延续了4.0以来的配置逻辑整体兼容性更好。所以如果你用的是JMeter 5.6或者6.x别再去翻那些2015年的博客去配什么server.rmi.port和-Djava.rmi.server.hostname了你的问题大概率是出在证书和防火墙这两个完全不同的维度上。搞明白自己版本的配置哲学比复制粘贴一页配置代码更重要。2.3 哪些压测场景真正需要分布式也不是所有压测都需要分布式。我在实际项目里总结下来大概就三类场景值得上第一类是真正的超大规模并发。比如单机线程数开到5000以上压测机CPU已经90%以上了但被测系统响应依然很快TPS还有上涨空间这时候你就需要Slave来分担压力。一般来说单台Slave撑住2000-3000并发是比较健康的超过这个阈值继续堆线程压测机自身反而会成为瓶颈。第二类是压测脚本本身比较复杂的情况。比如每个请求都做了大量前置数据处理、正则提取、JSON断言甚至嵌入了BeanShell或JSR223脚本这时候CPU消耗非常大单机哪怕只开1000线程都跑不动就必须拆分到多台机器上。第三类是模拟多来源场景。某些系统做了IP维度的限流或者安全防控单IP发大量请求会被对方直接拉黑这种情况分布式压测天然有优势每个Slave用不同IP发送请求更容易模拟真实用户来源。反过来如果你的压测目标就是几百并发被测系统本身也比较弱那完全没必要折腾分布式。分布式带来的网络开销、运维成本、结果同步问题会让简单的问题变复杂。3. 环境准备与前置条件3.1 硬件与网络规划分布式压测对机器配置没有绝对统一的标准但有一个大原则Slave机器的CPU主频不要太高但核心数要多内存要够。因为发送请求本身是IO密集和线程调度密集的工作。以我自己常用的配置为例一台4核8G的云主机跑JMeter 5.6单机开3000个线程做简单的HTTP GET请求CPU大概能压到70%-80%左右内存还剩不少。如果换成16核的物理机则能跑到5000线程以上但这时候已经不太建议继续堆线程数了。网络方面Master和Slave之间建议部署在同一个内网网段延迟不要超过几毫秒。因为每执行完一次测试循环或者每次采样结束Slave都要往Master回传数据如果网络延迟和丢包严重会出现数据回传超时也就是常见的“Error writing to server”问题。另外Slave和被压系统之间最好也是低延迟的稳定网络保证压测结果能反映真实的网络交互耗时而不是把公网抖动也算进去。端口这块要提前规划好。JMeter分布式默认需要开放几个端口一个是Slave端接收Master RMI调度的端口默认是1099另一个是Slave向Master回传结果的端口如果你不做额外配置JMeter会随机选择。这会给防火墙配置带来很大麻烦后面我会讲怎么固定这个端口。如果你们公司网络管控严格建议提前和运维确认端口放通范围避免压测前临时扯皮。3.2 JDK与JMeter版本一致性分布式压测里最容易忽略但又最致命的一个环境问题是各台机器上的JDK和JMeter版本不一致。JDK版本不一致最典型的后果是RMI序列化通信异常因为不同JDK版本的序列化ID、协议细节有差异。比如一台机器是JDK 8另一台是JDK 17Master往Slave发脚本或者Slave往Master回传结果时有时会莫名其妙地报ClassCastException或EOFException查半天发现就是版本不匹配。JMeter版本不一致更糟糕因为.jmx脚本本质上是一个XML描述文件高版本JMeter生成的脚本里可能包含了低版本不认识的配置节点或者引入了新的属性模块。实际表象就是Slave报“CannotResolveClassException”或者干脆脚本加载了一半就崩了。最省事的做法是所有参与压测的机器统一用同一个JMeter版本最好连补丁版本都一致JDK也用同一大版本。项目组可以做一个约定压测镜像模板统一打好环境任何新加Slave都从这个模板复制避免人工一台台安装带来的版本漂移。3.3 控制机和执行机的准备工作控制机Master的准备工作相对简单装好JDK和JMeter把写好的.jmx脚本放在一个固定目录确保启动时能正确读取。另外Master机器需要能够通过RMI访问到每一台Slave的1099端口如果只是单向能通那任务分发了也会卡住。执行机Slave的准备工作要注意几个细节。第一JMeter安装包解压后不要放在带中文或空格的路径下有些JMeter版本在Linux下对中文路径处理有兼容性问题Windows下相对宽松但也不建议冒险。第二Slave机器上不需要启动JMeter的GUI界面只需要确认bin目录下的jmeter-server脚本能正常启动。第三如果压测脚本里用到了外部数据文件比如CSV参数化文件必须把这个文件也拷贝到每一台Slave对应的相对路径下因为Slave执行脚本时读取数据文件是在自己本地读的Master传递的是脚本不会把数据文件一并传过去。这些前置工作看似琐碎但每一条都是我在实际项目中踩过的坑。提前花10分钟把每台机器的环境统一收口比压测进行到一半再排查问题要划算得多。4. 分布式压测核心配置实操4.1 修改jmeter.properties中哪些参数分布式压测的配置核心都集中在JMeter安装目录下bin/jmeter.properties文件里。很多人在这一步就是改一个remote_hosts就完事其实至少需要动以下几个配置项第一个是remote_hosts这个参数定义了Master要连接的Slave列表。比如你有3台SlaveIP分别是192.168.1.101、192.168.1.102、192.168.1.103那配置就是remote_hosts192.168.1.101:1099,192.168.1.102:1099,192.168.1.103:1099如果端口就是默认的1099可以省略不写端口号但建议显式写出来方便后续排查时一眼看到端口配置。默认情况下remote_hosts是127.0.0.1如果只配了本机IP那分布式压测就跑不到别的机器上。第二个是server.rmi.port这个参数决定Slave上的JMeter服务监听哪个端口来接收RMI请求。默认情况下JMeter不加这个参数时RMI服务端口是随机选的非常不利于防火墙放行和问题排查。建议在每一台Slave的jmeter.properties里都强制固定server.rmi.port1099这样1099端口就是Slave的固定服务端口。第三个是RMI回传结果的端口。JMeter 5.x版本中Slave往Master回传结果默认使用client.rmi.localport相关配置。为了固定这个端口可以在每台机器的jmeter.properties里加上client.rmi.localport1100注意1100并不是官方默认值这里的本意是你为Slave回传数据额外开一个固定的本地端口。我自己的习惯是Master上也把这个值配成1100然后在防火墙里放通所有机器之间的1100端口这样回传路径就固定了后续排查“结果不聚合”之类的问题时只需要看这一条端口链路上的连通性即可。第四个是server.rmi.ssl.disable。新版JMeter默认启用RMI SSL如果你在完全内网隔离、可控的压测环境里为了减少证书配置复杂度可以设置server.rmi.ssl.disabletrue关闭SSL后会简单很多但代价是RMI通信是明文传输。在内网压测环境问题不大如果涉及公网传输或者公司安全审计比较严格建议还是保留SSL并做好证书分发。要不要关是安全和效率的取舍问题没有绝对正确答案。4.2 证书与RMI密钥的生成和分发如果你选择保留SSL也就是不设置server.rmi.ssl.disabletrue那证书分发就是绕不开的一步。JMeter官方从4.0开始提供了一个脚本create_rmi_keystore.batWindows或create_rmi_keystore.shLinux运行后会在bin目录下生成rmi_keystore.jks文件。具体操作就是在Master和所有Slave上各自运行一次这个脚本生成各自独立的密钥库。需要特别注意的是JMeter 5.x版本中RMI通信的SSL验证机制要求Master信任Slave的证书同时Slave也要信任Master的证书。官方脚本生成的密钥库默认是自签名的如果你只是每台机器各自生成一个密钥文件那Master连Slave时还是会报untrusted server cert chain错误。解决这个问题有两条路。第一条路是简单粗暴的在每一台机器上把别人的rmi_keystore.jks拷贝过来覆盖自己的大家共用一个同样的密钥文件相当于用一个统一的身份标识这样彼此之间就能通过SSL验证。这也是我实际测试过最省事的方式。具体操作就是把Master上生成的rmi_keystore.jks复制到所有Slave的JMeter bin目录下或者反过来确保所有机器的这个文件是一模一样的。第二条路是按官方文档指引生成可信任的证书链这个方案更规范但要操作Java的keytool命令配置信任关系步骤繁琐而且多人协作时容易漏配。对于绝大多数自建压测环境来说共用密钥文件完全够用。4.3 环境变量与防火墙环境的最后一公里往往卡在防火墙和hosts解析上。先在每台机器上测一下网络连通性# 在Master上执行 ping 192.168.1.101 telnet 192.168.1.101 1099telnet能通说明TCP层没问题。如果不能通去检查Slave机器的防火墙规则把对应端口加入放行列表。Linux下可以用sudo firewall-cmd --add-port1099/tcp --permanent sudo firewall-cmd --add-port1100/tcp --permanent sudo firewall-cmd --reload如果是云主机还需要在安全组里额外放行这些端口。还有一点很少有人提但非常实用确保每台机器的/etc/hostsWindows是C:\Windows\System32\drivers\etc\hosts里Master的主机名和Slave的主机名能正确解析到对应IP。因为RMI通信走的是Java的远程调用它除了IP之外还会带主机名信息如果主机名解析不到或者解析到了错误IP即使TCP能通也可能报ConnectException。最简单的方式是把所有压测机器的主机名-IP映射统一加进每台机器的hosts文件里一劳永逸。4.4 启动顺序与验证正确的启动顺序很重要。先启动所有Slave再启动Master。Slave启动的方式是运行bin目录下的jmeter-server脚本# Linux/Mac ./jmeter-server # Windows jmeter-server.bat启动成功后会看到类似这样的日志Created remote object: UnicastRef [liveRef: [endpoint:[/192.168.1.101:1099](local),objID:[-7e1a6f3a:...]]]看到Created remote object字样说明Slave已经就绪正在等待Master下发任务。Master启动方式有两种。一种是用GUI模式启动JMeter后在“运行”菜单里选择“远程启动”或“远程全部启动”这种方式适合调试和小规模压测。另一种是用命令行模式jmeter -n -t test_plan.jmx -R 192.168.1.101:1099,192.168.1.102:1099 -l result.jtl-R参数可以直接指定远端执行机列表它会自动启动远程代理。这里注意用-R参数时远程列表优先级高于remote_hosts配置。使用Non-GUI模式更推荐因为它在压测时不会有界面刷新的开销数据采集更稳定。验证分布式环境是否正常的最快方法是在GUI模式里点击“远程启动”看每一台Slave是否正常返回结果树信息。如果日志里出现Starting remote engine并且最终能看到结果汇聚那说明环境基本OK了。5. 压测脚本设计与数据计算5.1 分布式模式下的脚本设计约束分布式压测中脚本设计和单机压测有一个核心差异你不能假设数据状态是共享的。举例来说如果你在脚本里用了一个计数器元件来生成唯一订单号单机模式下一切正常但分布式模式下每台Slave会各自独立维护一个计数器。这样就会出现多台机器生成重复订单号的情况。解决方案通常是给计数器加一个前缀或偏移量比如每台Slave的IP最后一位作为前缀保证每个进程生成的ID全局唯一。另一个常见问题是文件读写。压测过程中如果脚本有写文件的操作比如把每个请求的响应数据追加到本地日志在分布式模式下数据会分散写在各台Slave机器上。后续收集这些分散日志会非常麻烦。所以我建议分布式压测的脚本尽量避免在Slave端直接写文件统一把结果通过监听器的CSV输出功能汇聚到Master端或者用后端监听器直接把数据发送到InfluxDB这种监控系统里。参数化文件的处理也值得单独说。比如你用CSV Data Set Config从user.csv里读取登录信息这个文件必须复制到每台Slave机器上并且路径要和脚本里的相对路径一致。更稳妥的方案是把参数化数据放到一个固定的绝对路径下比如/opt/testdata/user.csv在所有Slave上保持相同路径。这样不管脚本怎么分发都能正确找到数据文件。5.2 线程组、并发量与执行机数量的计算很多人在设置分布式压测的线程池时犯迷糊到底线程数填多少总并发量怎么算其实简单总并发量 单台Slave线程数 × Slave数量。搞清楚这个公式之后剩下的就是反推。假设你的压测目标是模拟1万同时在线用户每台Slave的健康线程数是2000那么你需要5台Slave。这里还要考虑压测机自身的CPU利用率健康的压测机CPU应该控制在70%以下超过80%就可能出现GC频繁抖动导致压测数据失真。Ramp-Up时间的计算也有讲究。比如线程数是5000Ramp-Up时间设置为100秒那平均每秒钟会新增50个线程也就是每秒新增50个并发用户。如果被测系统的Connection Pool只允许1000个连接而你100秒才把这些连接全部发完那前100秒内压力是渐进式上升的。这时候聚合报告里的TPS曲线会呈现一个爬坡的过程这是正常的。我自己在项目里的习惯是先用单机跑一遍小规模冒烟测试观察平均响应时间和错误率再根据单机性能反推需要的Slave数量。比如单机2000并发时TPS是8000被测系统目标TPS是20000那理论上需要2到3台Slave就够了因为横向扩展后CPU不再是瓶颈每台Slave的吞吐能保持住。5.3 结果收集与监听器选择分布式模式下监听器的选择直接影响压测结果的可信度。很多监听器在GUI模式下使用很愉快但在分布式模式下就不靠谱了。比如“查看结果树”这种监听器如果不加约束它会把所有Slave回传的每个请求的完整响应数据都缓存在Master的内存里压测时长一长Master内存就爆了。所以执行正式压测时一律使用Simple Data Writer简单数据写入器配置CSV输出只记录关键字段比如时间戳、响应时间、状态码、线程名等。JMeter的分布式结果聚合还有一个特性如果Master上启动了聚合报告监听器那它收到的是一个“合并后的结果”也就是说所有Slave的数据会汇总到一份。这个设计在大多数场景下是合理的但要注意聚合报告在分布式模式下也会有精度损失问题。尤其是响应时间的百分比位数比如99th、999th在实时聚合时计算不够精确。更严谨的做法是在压测完成后基于CSV原始数据用Python或专用工具做二次统计这样得到的性能指标才足够精确。5.4 分布式模式下的参数化数据与CSV文件参数化数据在分布式压测中是个高频坑点。最常见的错误是把登录用户数据放在Master上的CSV里然后启动分布式结果Slave跑起来后发现没有用户名可用直接报错。原因前面已经提到脚本传过去了但数据文件没传。针对这个问题有几种解决方案。第一在每台Slave的相同路径下放置相同的数据文件。第二用JMeter的__CSVRead函数配合绝对路径读取。第三使用setUp线程组在压测开始前把数据一次性加载到内存通过${__P()}属性传递到各线程。方法三看起来很优雅但实现起来复杂度高而且如果数据量巨大Slave内存也吃紧。从实际经验看方案一是最可靠也最容易排障的直接把CSV文件分发到每台机器的固定目录脚本里使用这个绝对路径。比如所有Slave上文件都放/data/jmeter/users.csv脚本里写/data/jmeter/users.csv这样分布式的数据一致性就有了保障。另外一个数据一致性问题如果你每个线程循环了很多轮而CSV数据不够每条线程分配那后面几轮循环就会复用前面的行这可能会导致重复用户登录。这时候需要用CSV Data Set Config里的Sharing mode选项。比如设置为Current thread每个线程独立取数据设置为All threads则所有线程共享一个游标。分布式模式下这两种模式在每台Slave内部生效跨Slave之间依然是各自独立的游标。如果你要保证数据全局不重复还是得回到加前缀或者按IP分片这类预处理思路上来。6. 高频问题与排查技巧实录6.1 java.io.IOException: Error writing to server这是分布式压测中最高频的报错没有之一。字面意思是“往服务器写数据时出错”但造成这个问题的原因五花八门我遇到过至少四种第一种是Master和Slave之间的网络出现中断或者拥塞尤其是压测规模较大、回传数据量激增时容易触发。排查方法是先看Master的GC日志和内存占用如果Master内存经常飙升加大JMeter的JVM堆内存修改jmeter.bat或jmeter.sh里的HEAP参数比如HEAP-Xms4g -Xmx8g。第二是回传端口没有固定导致防火墙随即拦截一部分奇怪的临时端口流量解决办法就是前面说的设置client.rmi.localport固定回传端口。第三是Slave的CPU被打满了数据来不及回传积压在本地队列里最终超时后报错。这种情况需要降低单台Slave的线程数增加Slave数量来分担压力。第四是Master上的结果监听器过于吃内存比如开着结果树一旦结果回传量超过内存承载阈值Master直接放弃写入。所以排查这个问题的顺序应该是先看Master内存和GC再看Slave CPU再看网络丢包和延迟最后才是端口放通情况。不要一看到这个报错就去重装JMeter或者重启机器。6.2 连接超时、Connection refused 类问题这类问题一般集中在刚搭建环境时。在Master上启动远程执行机时直接青一个红一个提示连接超时或者拒绝连接。排查步骤非常固定先telnet测试Slave的1099端口通不通不通则检查防火墙和安全组。通了再确认Slave是否启动成功有没有看到Created remote object日志。再看jmeter.properties里remote_hosts有没有写错包括IP和端口。最后检查hosts解析和证书配置是否一致。还有一个隐藏较深的原因Slave机器上开了多个JMeter进程占用了同一个1099端口。特别是之前压测异常退出后JVM进程没有完全释放端口。用netstat -anop | grep 1099查一下占用端口的PID把残留进程杀掉再重启jmeter-server就好了。6.3 远程启动成功但结果不汇聚有朋友遇到过分布式执行成功了Slave端日志也显示在发请求但是Master的聚合报告里看不到数据或者只有部分Slave的数据。这种情况大概率是结果回传路径断了但你没有受到异常报错。原因往往是Master端的client.rmi.localport和Slave端对不上或者Slave到Master的1100端口被防火墙拦截。注意回传数据的链路是从Slave主动连回Master的所以你要在Master的防火墙里放行1100端口的入方向。另一个常见原因是Master上的监听器没有配置好。分布式模式下如果脚本里没有加聚合报告或Summary Report这类能汇总远程结果的监听器那Master就只跑脚本不展示数据。所以脚本里记得保留聚合报告监听器。6.4 Slave端ClassNotFound 或脚本加载失败这类问题的根源几乎都是版本不一致。排查方法很直接让所有Slave执行jmeter -v对比输出的版本号严格一致。如果版本不同重新安装统一版本。另外如果脚本里用到了第三方插件比如PerfMon Metrics Collector那每台Slave的lib/ext目录下都要有对应的插件jar包否则会报找不到类。6.5 高并发场景下数据错乱、登录态失效、TPS上不去这一类问题常常被误判为“分布式配置问题”但实际上可能是测试数据设计问题。分布式模式下如果多台Slave同时发送相同的账号登录很容易触发系统的单点登录互踢逻辑导致一堆401或会话失效。解决思路是给每一台Slave准备独立的账号池或者用__threadNum这种函数结合机器信息生成唯一用户。TPS上不去还有一种被忽视的情况Slave与被测系统之间的网络带宽限制了吞吐量。比如你开了5台Slave目标系统带宽是1Gbps而单台Slave就能跑到300Mbps5台Slave整体压过去时很容易在交换机或链路上出现拥塞。排查方法是在压测期间观察Slave的网卡流量如果已经打满说明瓶颈在网络上而不是在系统本身。7. 常见报错速查表与故障处理顺序7.1 速查表报错信息直接原因排查顺序解决方案Error writing to server回传数据链路异常Master内存 → Slave CPU → 网络 → 端口调大JVM堆降低线程数固定回传端口放行防火墙Connection refusedSlave未启动或端口不通telnet → 服务日志 → 防火墙启动jmeter-server检查remote_hosts放行端口Connection timed out防火墙拦截或网络不通网络连通性 → 安全组放行1099/1100端口检查跨网段路由Untrusted server cert chainSSL证书不一致核对各机器jks文件统一复制同一个rmi_keystore.jksCannotResolveClassException版本差异或插件缺失对比版本 → 检查插件统一JMeter和JDK版本同步插件jar包OutOfMemoryError堆内存不足查看GC日志调整HEAP参数减少结果缓存No route to hosthosts解析异常hosts文件 → DNS手动添加主机名IP映射Remote engine already started重复启动Slave检查进程列表杀掉旧进程或换端口这张表覆盖了我在项目里遇到的大多数问题。需要强调的是报错信息只是表象真正排查时必须从链路层层往下追不要一上来就怀疑JMeter本身。7.2 推荐排查顺序如果压测过程中出了问题我建议按照“环境连通 → 版本一致性 → 资源水位 → 脚本逻辑”的固定顺序来排查而不是凭感觉抓一把。第一步确认Master和所有Slave之间网络是通的端口放行没问题。这一步花费5分钟能过滤掉一半以上的“分布式环境问题”。第二步确认各机的JMeter、JDK版本统一关键配置文件一致。第三步压测过程中监控Master和Slave的CPU、内存、网络IO定位是不是资源水位已经打满。第四步才回到脚本本身检查有没有不合理的断言、过度的日志输出、不合理的test action。这个顺序看起来简单但大多数排查失败的情况都是因为跳过了前两步直接在脚本里找了半天结果折腾一圈才发现是防火墙把端口拦了。8. 分布式压测的调优思路与个人经验分布式压测的调优核心不在于把JMeter本身调到飞起而在于让每台Slave都保持稳定输出。我在实际项目中总结出几个很有效的调优手段。第一是合理设置JVM参数。JMeter默认的堆内存是1G对大规模压测来说远远不够。按经验Slave机器的内存如果为8G建议设置HEAP-Xms4g -Xmx4gMaster机如果同时承担结果汇总可以给到-Xms8g -Xmx8g。设置位置在jmeter启动脚本里的HEAP变量。GC方式建议使用G1JMeter 5.x默认就是G1不需要额外调整。第二是关闭不必要的监听器。执行正式压测时GUI模式和监听器能不开就不开用-n命令行模式加上-j日志参数把压测结果输出到文件走CSV格式。这样能把JMeter自身的开销降到最低。第三是谨慎使用断言。每个响应断言都会消耗额外的CPU时间用于匹配压测规模上来后这条开销会被放大很多倍。能用状态码判断的就用状态码判断少用响应文本匹配。第四是压测过程中建议实时监控Slave的CPU温度和资源占用如果发现某台Slave明显比其他机器慢考虑是不是虚拟机邻居抢占资源或者性能衰退及时把问题机器摘除不要让它拖累整体数据质量。还有一个实用技巧如果压测脚本涉及Beanshell建议在正式执行前转换成JSR223Groovy。Beanshell性能较差且JMeter官方不推荐在新测试计划中使用JSR223脚本引擎的性能能高出几个数量级这在分布式场景下对保持每台Slave的吞吐有很大帮助。9. 写在最后的经验总结做完多次分布式压测后我最深的体会是分布式压测其实并不难难点在于环境维护和问题排查的耐心。只要把版本一致、端口放行、证书统一、数据分发这四件事做扎实整个压测过程就已经成功了80%。剩下的20%才是脚本设计、数据校准和结果分析。最后分享一个小技巧建议把所有压测机器的配置做成自动化脚本或者镜像模板不管是jmeter.properties、jmeter-server启动参数还是hosts映射、防火墙规则全部提前固化。这样下次再搭环境或者临时扩容一台Slave十分钟内就能复现整套环境不用再从头人工配置一遍。如果后续要扩展也可以考虑把JMeter分布式压测和监控系统打通比如通过InfluxDB Grafana实时展示TPS、响应时间、系统资源曲线把压测过程做成可视化的数据报表这样交付给项目组时更有说服力也方便压测后的性能瓶颈分析。这些内容如果大家感兴趣后面可以再单独写一篇来详细展开。
返回列表