Tcp keepalive 引發的 Connection reset by peer 異常


業務需要,為了提供高性能的查詢服務,引入了一款高速搜索服務,客戶端的鏈接使用的HTTP,測試環境使用一切正常,但上線后幾乎每天都會發生異常Connection reset by peer。

具體場景如下:

兩台業務服務器,用客戶端(基於HTTPClient,實現了長連接)連接的搜索服務集群(集群有三台機器),客戶端與服務器分別部署在不同的網段,異常會有規律的出現: 每天9點左右會發生異常Connection reset by peer. 而且是連續有三個

Connection reset by peer Caused by: java.io.IOException: Connection reset by peer         

at sun.nio.ch.FileDispatcherImpl.read0(Native Method)         

at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:39)         

at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223)         

at sun.nio.ch.IOUtil.read(IOUtil.java:197)

這個異常到是很好解決,引入重試機制,捕獲這個異常后重新發起請求,第二次都會成功,但這是治標不治本,還需要進一步探究問題的根源。

於是乎,查官方文檔、比對代碼、讓運維同事幫着抓包。。。想了多種方法,經過若干天的努力,最終發現這個異常是和keepalive這個關鍵詞相關。

keepalive 分兩種:

Http的 keep-alive參數Tcp keepalive配置

HTTP1.1中默認啟用"Connection: Keep-Alive",表示這個HTTP連接可以復用,下次的HTTP請求就可以直接使用當前連接,從而提高性能,一般HTTP連接池實現都用到keep-alive,這個一般是默認選項;

​TCP的keepalive的作用和HTTP中的不同,TPC中主要用來實現連接保活,相關配置主要是net.ipv4.tcp_keepalive_time這個參數,表示如果經過多長時間(默認2小時)一個TCP連接沒有交換數據,就發送一個心跳包,探測下當前鏈接是否有效,正常情況下會收到對方的ack包,表示這個連接可用。

實際線上環境,業務服務器和搜索服務集群之間有一道防火牆,而防火牆策略定義空閑連接超時時間為1小時,與上面提到的linux服務器默認的2小時不一致。

由於我們當前系統晚上訪問量較少,導致某些連接超過2小時沒有使用,在其中1小時后防火牆自動就終止了當前連接,到了2小時后服務器嘗試發送心跳保活連接,直接被防火牆攔截,若干次嘗試后服務端發送RST信號中斷了鏈接,而此時的客戶端並不知情;當第二天早上使用這個失效的鏈接請求時,服務端直接返回RST,客戶端報錯Connection reset by peer,嘗試了集群中的三台服務器都返回同樣錯誤,所以連續報了3個相同的異常。解決方案也比較簡單,修改服務端keepalive超時配置,小於防火牆的1小時即可。

 


免責聲明!

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



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