Jmeter的客戶端實現與Keep-Alive

火顏發表於2021-02-02

Jmeter的客戶端實現與Keep-Alive

沒有時間的朋友直接讀結論即可。

0. 結論

  1. 當客戶端實現為Java,使用Keep-alive時

    1. Vuser越大,保持的時間越短,且tcp連線會斷不完全,造成雙倍甚至3倍Vuser連線的情況。

    2. Vuser越小,保持的時間越長,但過幾分鐘甚至10幾分鐘後,tcp連線還是會變。

      這個現象的原因不詳。

  2. 當客戶端實現為HC4,使用Keep-alive時

    1. 修改jmeter.propertieshttpclient4.time_to_live的數值即可保持連線時間。單位為ms
    2. httpclient4.time_to_live的值為0時,為永久保持
    3. Jmetr 5.3以下的版本,預設保持間為2s,5.3以上版本更改為60s。

以上的結論都基於服務端快速響應,不涉及超時時間等問題。

1.緣起

1.1 起因

起因是我需要使用Jmeter傳送HTTP請求,並且保持長連線。

再細化下需求,保持多久的長連線?

  1. 固定時長,到時間自動釋放
  2. 永久時長,只要不空閒超時

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個客戶端實現方式呢?我查詢了官方文件,貼在下面。

Jmeter客戶端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 迷惑點

到目前為止,我們需要解決的問題

  1. HC4 的長連線時間 怎麼設定?
  2. 永久連線(使用Java實現)為什麼會主動釋放tcp?

3. stack overflow&看原始碼

檢視Jmeter的原始碼原始碼和版本下載地址

3.1 HTTPJava

首先我去看了使用Java實現HTTP? 直接看HTTPJavaImpl.java即可

在論壇看到這麼個帖子

我的web後臺是沒有設定60s超時時間的,檢視http的報文也沒有max的引數。-----至此,問題無法解決

配置引數

通過HTTPJavaImpl.java可以看出,只有httpsampler.obey_contentlengthhttp.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進行更改了。

bug64289變更記錄

接下來就是實驗,改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了

參考

文章1

相關文章