JMeter并发上不去?不是服务器扛不住,可能是压测机自己先崩了——Locust和k6实测对比

🔑 关键词:JMeter,Locust,k6,性能测试,并发测试

📖 摘要:压测时JMeter线程一高CPU就满?本文从真实测试经历出发,对比JMeter、Locust和k6在并发模型、资源占用上的差别,分享分布式压测步骤和客户端瓶颈定位方法。

JMeter并发上不去?不是服务器扛不住,可能是压测机自己先崩了——Locust和k6实测对比

图片

先说个背景吧。我之前在一家做企业服务软件的公司,主要搞发布前的压测。有一回要模拟3000个用户同时登录,给的是一个稍微复杂点的登录接口,会调用验证码服务和账号服务。当时我用JMeter写脚本,HTTP请求加JSON提取再加断言,逻辑根本不算多。结果线程数加到1200,压测机的CPU直接100%,GC日志刷得飞快,服务端CPU平均才22%左右。项目经理当时问我“是不是服务器扛不住”,我说实话挺尴尬的,因为其实是压测机先挂了。那台压测机是云上8C16G,服务端才4C8G,没人想到客户端会成为瓶颈。后来我换成Locust重新写了同样的脚本,单进程2500虚拟用户都能跑起来,服务端CPU终于到40%以上,问题才真正开始显形。

图片

这段经历让我好好想了想JMeter的并发模型。JMeter每个虚拟用户对应一个Java线程,而Java线程真不轻,默认栈大小就1MB,1000个线程光栈内存就要1G,还没算请求上下文和断言产生的对象,加上GC本身消耗,单机想压到3000用户非常吃力。而Locust用的是gevent协程,遇到网络I/O就让出CPU给其他协程,所以它能模拟的用户数能高出一个量级,代价就是这些虚拟用户更像“伪并发”。如果你的脚本里全是同步等待或者CPU密集的RSA签名计算,反而会把event loop卡死,我跑过一个加密接口,里面要循环做签名,Locust只跑出230 RPS,JMeter用它的Java加密采样器能到560 RPS。所以说到底,别一听Locust并发高就盲目换,看你脚本主要是在等I/O还是在做计算。

图片

如果你已经决定用Locust压真实业务,我这里有几个参数可以直接抄。脚本里User类尽量设置wait_time为between(1, 3)这种接近真实操作的间隔,不然请求像风暴一样瞬间全打过去,压出来的结果根本不是稳态性能。启动时用无界面模式:locust -f login_test.py --headless --users 2000 --spawn-rate 50 --run-time 15m,意思是每秒只增加50用户,花40秒慢慢爬升到2000,这样能观察到服务器从空闲到过载的过程。更大的规模需要分布式压测,Master节点跑locust -f login_test.py --master --expect-workers 4,再准备4台Worker各跑locust -f login_test.py --worker --master-host=192.168.1.10,别在一台机器上无脑加用户数,内存和文件句柄会先爆。压测期间我会额外盯压测机自己的监控,如果压测机CPU已经到80%以上,而服务端负载始终不到30%,十有八九是测试工具又成为瓶颈了。

图片

我之前在一个静态Nginx接口上做过一个不太严谨的横向测试,300并发持续2分钟,JMeter单机RPS大约4200,压测进程内存占用2.1G;Locust加上--processes 2跑出来RPS大概4100,内存只有300M;k6用--vus 300 --duration 2m跑,RPS能到5200,内存180M。这个结果不黑谁,只是资源占用差异实在太明显。拿自己的4C8G办公本当压测机,却要用JMeter跑一万并发,基本就是自己跟自己过不去。但JMeter的位置还在,它支持的协议多,断言、正则提取、JDBC采样、Java采样这些东西很全,适合处理复杂报文和需要重逻辑校验的场景。k6呢,脚本是JS,可以放Git仓库里跟代码一起走,CI阶段配合thresholds直接让压测失败,比如http_req_duration的p(95)超过500ms就中止,这个能力JMeter要搞InfluxDB和Grafana才玩得转。

图片

最后说一个我判断业务瓶颈自己的土办法。压测结果异常时,不要只盯着平均响应时间。先看P95和P99,再看客户端资源百分比;如果客户端没事,服务端也没满,那大概率是链路中间某个网络设备或者依赖服务出了鬼。有一个案例我记得特别清楚,App的上传接口压测到150并发就大量超时,服务端CPU和内存都很低,最后查出来是反向代理的keepalive超时时间设置得太短,和工具选型一点关系都没有。所以性能测试最后找的往往不是工具的问题,而是你的系统假设哪里不成立。我现在的习惯是:基线压测用JMeter,复杂用户行为用Locust,CI里跑冒烟用k6,混合着来,反而不纠结要不要换掉谁了。

图片

先写这些,有具体场景想问的话评论区聊。