Jmeter的客户端实现与Keep-Alive
0. 结论
-
当客户端实现为Java,使用Keep-alive时
-
Vuser越大,保持的时间越短,且tcp连接会断不完全,造成双倍甚至3倍Vuser连接的情况。
-
Vuser越小,保持的时间越长,但过几分钟甚至10几分钟后,tcp连接还是会变。
这个现象的原因不详。
-
-
当客户端实现为HC4,使用Keep-alive时
- 修改
jmeter.properties
的httpclient4.time_to_live
的数值即可保持连接时间。单位为ms - 当
httpclient4.time_to_live
的值为0时,为永久保持。 - Jmetr 5.3以下的版本,默认保持间为2s,5.3以上版本更改为60s。
- 修改
以上的结论都基于服务端快速响应,不涉及超时时间等问题。
1.缘起
1.1 起因
起因是我需要使用Jmeter发送HTTP请求,并且保持长连接。
再细化下需求,保持多久的长连接?
- 固定时长,到时间自动释放
- 永久时长,只要不空闲超时
1.2 初步尝试
既然要做Jmeter的HTTP长连接,肯定就是要勾选keep-alive
接着就去进行测试压测了,结果发现压测的端口在不断的变化,并没有实现一个长连接的效果。
查看Jmeter压力机 查看具体端口
-
windows的话使用
netstat -ano | find "ip端口" | find "ESTABLISHED" | find "IP地址"
-
linux的话使用
ss -ant | grep "ip端口" | grep "ES" | grep"IP地址"
只看端口变化还是有一定的问题,遂抓取压测时候的包查看。
抓包命令:
- windows 使用wireshark抓包
- linux 使用 tcpdump
tcpdump -i 网卡名 -w 保存的报文名字.pcap
之后使用wireshark解析
一看果然,只有在一个时间段进行了保持连接,之后客户端就主动释放了
看下图,我只有3个Vuser,如果一直保持了连接,是不可能建立出7个连接的。
观察了下时间,正好2秒释放掉的。
如法炮制,我观察了好几个tcp连接,都是2秒钟就主动释放了。
所以有理由推测,这个保持时间是个可配置项。
1.3 Jmeter客户端实现
想到时间可以配置,我来到了HTTP的高级页面,在这里,发现了HTTP的客户端实现方式。
- HttpClient4 简称HC4
- Java
- 空
为什么会有3个客户端实现方式呢?我查询了官方文档,贴在下面。
简单的来说就是:
- HC4 实现 -----多数情况都在使用的,功能丰富且细化。
- Java实现 -----在实现HTTP时候会有限制
- 空 ---- 读取配置文件来决定使用什么,默认是HC4
1.4 Java+keep-alive?
之前使用的是HC4+keep-alive 无法一直保持,那么Java + keep-alive呢?抱着这个想法,我测试了下。
Vuser 我依然给了3个,下面是线程组配置
结果非常惊喜,抓包查看可以一直保持!
此处其实是有问题的,先埋个坑。
2. 压力测试
2.1 测试
基于前面的测试报文,很开心,于是直接将这种方式进行了压力测试。
设置Vuser为200,诡异的事情发生了,压力机报了好多异常错误信息,查看jmeter.log也没有报错信息。一时间不知所措。
日志就不截图了,和上图一样。
于是,我开始抓包,抓包看。
结果发现长连接没有保持住,能过滤出tcp的连接好几百,正常应该就是200个连接一直在保持。
但是报文还是看出几个点:
- tcp保持时间:有的保持了2s,有的10s,有的15s,没有规律,
- tcp释放:每次都是由Jmeter主动释放(主动发送Fin)。
查看压力机的端口使用情况:
明显是TIME_WAIT过多,为了更进一步的确定,我产生了jtl 和 debug级的log。
2.1 产生jtl和debug级日志
修改日志等级
修改bin/log4j2.xml
将info 修改为debug
产生jtl和log
linux 执行命令 jmeter -n -t ./xxxxx.jmx -l test.jtl -j debug.log
使用GUI的Jmeter查看jtl
在测试计划里添加 查看结果树,导入产生的 jtl
确实是产生了好多失败的请求,查看某一个请求,发现HTTP的Message为 无法分配请求地址。
这也侧面证明了确实是端口不够用,导致无法请求了。
2.3 迷惑点
到目前为止,我们需要解决的问题
- HC4 的长连接时间 怎么设置?
- 永久连接(使用Java实现)为什么会主动释放tcp?
3. stack overflow&看源码
查看Jmeter的源码源码和版本下载地址,
3.1 HTTPJava
首先我去看了使用Java实现HTTP? 直接看HTTPJavaImpl.java
即可
在论坛看到这么个帖子
我的web后台是没有设置60s超时时间的,查看http的报文也没有max的参数。-----至此,问题无法解决
配置参数
通过HTTPJavaImpl.java
可以看出,只有httpsampler.obey_contentlength
和http.java.sampler.retries
参数是影响JavaHttp的实现的。
通过字面和Jmeter手册
- httpsampler.obey_contentlength : 服从内容长度
- http.java.sampler.retries :重试次数,默认为0,不进行重试
无关紧要,往下走。
sample函数
sample为核心函数,负责创建连接,接收信息的
结合debug的日志,我们几乎可以断定就是在块发生了IO异常。
谁抛出的异常呢?应该是setupConnection
函数
setupConnection函数
猜测是这里出了问题。
看源码也是没能找到为什么java的会主动释放tcp。影响java的http实现就是2个参数,之后又看到了一个bugbug55023,说的是一个其他参数影响了Java实现的HTTP的吞吐值,这里怀疑也可能是某个未知bug。并且论坛在讨论相关实现的时候都在推荐HC4,不推荐JAVA(实现的功能少)。
至此,我仍然没有找到为什么在使用JAVA实现 + keep-alive时候,会不断的释放+新建TCP连接,如果有大佬清楚,麻烦留个言,讨论下
3.2 HTTP HC4
既然JAVA的路走不通了,转回头研究下HC4的实现
查看Jmeter的配置文件jmeter.properties
发现几个参数很是可疑。
378 httpclient.timeout
437 httpclient4.idletimeout
445 httpclient4.time_to_live
去手册查看得知
也即是
- httpclient.timeout : 这个是socket的连接超时 时间,默认0是不超时的
- httpclient4.idletimeout:在服务器没有发keep-alive的情况下,http的连接超时时间,也就是在服务器没有发keep-alive的情况下,还能保持多少秒。默认是不保持。
- httpclient4.time_to_live: http的生存时间,默认时间60s。
这个httpclient4.time_to_live
好像是决定的参数,看了Jmeter的配置,怎么是2000,不是6000呢?
2000? 想起了第一次抓包的tcp时间就是2s。看来就是这个参数了。那怎么是2000,不是6000呢?
我查看了Jmeter版本,原来本地用的是5.2.1版本,而5.3.1时候Jmeter将这个视作bug进行更改了。
接下来就是实验,改httpclient4.time_to_live之后确实可以固定长度的连接时长,但是如何大的时长和永久呢?
TIME_TO_LIVE
看了下Jmeter源码HTTPHC4Impl.java
,发现了下面的语句。
这个语句很有意思,这定义了一个 **int **类型的 int类型的最大值是 2 的 31 次方 - 1 = 2147483648 - 1 = 2147483647 Integer.MIN_VALUE = -2147483648
2147483647/1000/3600/24 = 24.8 也就是说可以保持24.8天,已经满足使用了。
但是我们仍往下查看,发现只是将TIME_TO_LIVE传给了HttpClientBuilder
接下来去看下HttpClient的源码 HttpClientBuilder
类。
可以看到,HC4是以long进行接收的,但是Jmeter把范围缩小了,变为了int。
但是还是没解决永久的连接啊,于是突发奇想,试试值为0呢,没想到竟然可以使用,
我测试了半天发现仍可以保持连接,其实感觉也就是不合法的值为MAX_VALUE了,这个属于猜测,我没有找到异常数值的相关的代码。
小结
要保持长连接选择 HC4 实现,不要选择JAVA,连接时长设置httpclient4.time_to_live
该参数。
在回过头看看官方的解释文档,无法控制如何重新使用连接,这句话好像有所解释,但是我理解的不深入。所以还是使用HC4吧,别用Java了
转:https://www.cnblogs.com/wfer/archive/2021/02/02/14360723.html