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了