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了