記錄一次大量CLOSE_WAIT的情況


  近期的項目中,有一個特殊的需求,對於每個客戶端程序有若干個機構,對於每個機構有不同的客戶端證書,程序間隔一段時間向服務端進行請求,根據請求的成功與否更新各機構的狀態(如正常,證書未配置,證書過期等)。

  實際投入測試環境進行使用的時候,運行了一段時間之后,客戶端程序出現了大量的CLOSE_WAIT的情況,導致壓力測試無法正常進行。

  對相關的代碼進行了檢查之后,發現了之前的做法是對於每一個機構,維護一個RestTemplate對象,在其中進行讀取證書等操作。懷疑和大量的restTemplate有關這個問題,因為本地開發的時候基本只有幾個機構進行測試,所以未出現以上情況。根據CLOSE_WAIT出現在客戶端的情況進行分析,是服務端發起了關閉連接的請求,而客戶端進行了響應之后,接收了數據完成后並沒有進行關閉,導致出現了CLOSE_WAIT。

  首先增加了連接池的參數 setValidateAfterInactivity(如下),發現不起作用。

PoolingHttpClientConnectionManager connectionManager = new
                    PoolingHttpClientConnectionManager(socketFactoryRegistry);
            connectionManager.setValidateAfterInactivity(200);

  然后在初始化HttpClient時增加了參數 evictIdleConnections ,發現生效。

            CloseableHttpClient httpClient = HttpClients.custom()
                    .setSSLSocketFactory(csf)
                    .setConnectionManager(connectionManager)
                    .evictIdleConnections(2, TimeUnit.SECONDS)
                    .build();

 

  通過分析源碼發現,RestTemplate在不做額外配置的情況下,會默認開啟KeepAlive,而服務端不進行額外配置的時候,不會返回額外的內容,此時客戶端進行了相關的判斷之后,如果響應頭沒有Keep-Alive會返回-1,即認為默認不釋放,后續服務端進行相應的連接的斷開時,客戶端認為可重用,就不進行清理,導致一致處於CLOSE_WAIT狀態,而由於使用了大量的RestTemplate,導致大量的CLOSE_WAIT出現。

連接池的配置不起作用是因為底層調用的是連接池的release方法,而release方法內部會進行相應的判斷,如果發現是可重用的鏈接,就不會釋放。

CloseableHttpClient的配置生效是因為底層是查看是否過期,如果過期,則調用關閉方法。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM