天天看點

(幹貨)一次httpclient的close_wait問題的探讨

(幹貨)一次httpclient的close_wait問題的探讨
(幹貨)一次httpclient的close_wait問題的探讨

從圖中可以看出,如果用戶端被動關閉連接配接,且沒有向伺服器端發送FIN,則會一直處于CLOSE_WAIT狀态。

(幹貨)一次httpclient的close_wait問題的探讨

處理伺服器在處理完請求,與後端Nginx之間的連接配接仍然保持着CLOSE_WAIT狀态,個數為256(最大連接配接數)。

        原因:後端Nginx設定keep-alive長連接配接,在處理完處理伺服器請求後,由于keep-alive長連接配接逾時設定Nginx伺服器主動關閉了連接配接,處理伺服器端被動關閉,與後端Nginx間的連接配接處于CLOSE_WAIT狀态。根據查閱資料,大量的CLOSE_WAIT連接配接會占用系統資源,會造成連接配接阻塞,當新的請求到達時無法建立新的連接配接,真的是這樣嗎?為了驗證這一說法,做了以下實驗:

      (1)為了便于觀察端口的變化,将後端Nginx keep-alive最大連接配接數設定為10。

      (2)向系統發起10個請求,如圖所示建立起10個連接配接後處于CLOSE_WAIT狀态。

(幹貨)一次httpclient的close_wait問題的探讨

      (3)再向系統發起第11個請求時,原來的62454端口的連接配接斷開。 

(幹貨)一次httpclient的close_wait問題的探讨

      (4)配置設定新的端口62470建立新的連接配接。

(幹貨)一次httpclient的close_wait問題的探讨

驗證結論:系統雖然存在大量的CLOSE_WAIT,但它并不會造成連接配接阻塞,在新的請求到達時,舊的CLOSE_WAIT連接配接會斷開。這是因為HttpClient有這樣的機制,會自動清理CLOSE_WAIT狀态的連接配接。

然而,在測試中還遇到了另外一個CLOSE_WAIT問題卻造成了連接配接阻塞,這是為什麼呢?請看接下來問題2的分析。

(幹貨)一次httpclient的close_wait問題的探讨

向處理伺服器發起大量對象名不存在的請求,處理伺服器與後端Nginx之間也保持CLOSE_WAIT狀态,但是新的請求發起時,原來CLOSE_WAIT連接配接并沒有斷開,當達到Nginx設定的最大連接配接數256時,系統将不能再建立連接配接處理新的請求。為了定位原因,做了以下實驗。

 (1) 向系統發起對象名不存在的一個錯誤請求,處理伺服器與後端Nginx之間的建立連接配接

(幹貨)一次httpclient的close_wait問題的探讨

 (2)Nginx在keep-alive逾時後主動關閉連接配接,處理伺服器與Nginx連接配接狀态變為CLOSE_WAIT

(幹貨)一次httpclient的close_wait問題的探讨

 (3)再次向系統發起對象名不存在的錯誤請求,舊的連接配接一直保持CLOSE_WAIT狀态  

(幹貨)一次httpclient的close_wait問題的探讨

根據以上結果可以看出,CLOSE_WAIT狀态的連接配接并沒有被斷開,這和問題1的驗證結果是相悖的。它們的差別是什麼呢? 

 (4)向NOS伺服器再發起一個正确請求,如下所示,處理伺服器與Nginx之間的連接配接由ESTABLISHED狀态最後變為CLOSE_WAIT。

(幹貨)一次httpclient的close_wait問題的探讨

 (5)再發起新的正确請求,原來的57826端口的連接配接斷開,在57846端口建立新的連接配接。

(幹貨)一次httpclient的close_wait問題的探讨

 HttpClient有清理CLOSE_WAIT狀态的機制,那為什麼錯誤的請求産生的CLOSE_WAIT不能被清理呢?檢視處理伺服器使用HttpClient代碼,發現在處理異常請求部分的代碼中,沒有讀取後端tobie處理結果傳回body的操作,而根據Httpclient的處理機制,隻有在讀body操作後才會觸發HttpClient Manager回收連接配接,否則會被認為該連接配接一直在處理請求。是以在處理異常請求部分的代碼中增加response. getEntity().consumeContent()方法讀body操作。

(幹貨)一次httpclient的close_wait問題的探讨
(幹貨)一次httpclient的close_wait問題的探讨

轉載于:https://www.cnblogs.com/andashu/p/6290066.html