業務需要,為了提供高性能的查詢服務,引入了一款高速搜索服務,客戶端的鏈接使用的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 分兩種:
TCP的keepalive的作用和HTTP中的不同,TPC中主要用來實現連接保活,相關配置主要是net.ipv4.tcp_keepalive_time這個參數,表示如果經過多長時間(默認2小時)一個TCP連接沒有交換數據,就發送一個心跳包,探測下當前鏈接是否有效,正常情況下會收到對方的ack包,表示這個連接可用。