排查okhttp3的unexpected end of stream on Connection異?!揪W(wǎng)絡(luò)三次握手+四次揮手實(shí)戰(zhàn)分析】

某個(gè)微服務(wù)上線后,經(jīng)常拋出unexpected end of stream on Connection異常。懷疑是服務(wù)端斷開(kāi)長(zhǎng)鏈接,而客戶端依舊使用該連接調(diào)用。

調(diào)用鏈路如圖所示:

image.png

1. 臨時(shí)方案

根據(jù)異常信息定位到:服務(wù)端長(zhǎng)鏈接失效。客戶端依舊使用失效的長(zhǎng)鏈接去訪問(wèn)。

當(dāng)前的解決方案是:增加重試機(jī)制:retryOnConnectionFailure(true),當(dāng)客戶端使用失效的長(zhǎng)鏈接訪問(wèn)服務(wù)器失敗時(shí),重新訪問(wèn)。

但是這個(gè)是臨時(shí)的解決方案,可以使得業(yè)務(wù)不受影響,但是依舊無(wú)法解決服務(wù)端長(zhǎng)鏈接失效的問(wèn)題。

2. 問(wèn)題分析

2.1 服務(wù)端長(zhǎng)鏈接失效時(shí)間

登錄服務(wù)器(因?yàn)槭俏⒎?wù)調(diào)用,服務(wù)器自己是可以登錄上的)。

cat /proc/sys/net/ipv4/tcp_keepalive_time

但得到的結(jié)果是默認(rèn)的7200秒。

2.2 wireshark抓包分析

登錄服務(wù)器,使用tcpdump命令抓包分析,工具的使用詳見(jiàn)——TCP抓包分析—以及wireshark工具下載使用

image.png

三次握手和四次揮手的文章

  1. 客戶端經(jīng)過(guò)3次握手過(guò)程和服務(wù)端建立長(zhǎng)鏈接;
  2. 在8s內(nèi)長(zhǎng)鏈接沒(méi)有請(qǐng)求,服務(wù)端發(fā)起了四次揮手(FIN);
  3. 客戶端收到FIN后,發(fā)送ACK確認(rèn)收到;
  4. 客戶端通知應(yīng)用程序是否給服務(wù)器發(fā)送FIN時(shí);okhttp3使用該連接進(jìn)行通信;
  5. 發(fā)生RST過(guò)程,于是拋出了上述的異常。

下面是一個(gè)鏈接正常的建立和銷(xiāo)毀:

image.png

可以看到,當(dāng)該鏈接8s內(nèi)無(wú)數(shù)據(jù)時(shí),服務(wù)端會(huì)主動(dòng)的斷開(kāi)連接。

由上述抓包分析可知:關(guān)鍵點(diǎn)8s內(nèi)無(wú)請(qǐng)求訪問(wèn),服務(wù)器斷開(kāi)長(zhǎng)鏈接;

3.2 代碼配置排查

項(xiàng)目使用的是SpringCloud全家桶進(jìn)行開(kāi)發(fā)。替換了tomcat服務(wù)器使用了undertow服務(wù)器。Spring Boot 內(nèi)嵌容器Undertow取代tomcat

查看配置信息時(shí),發(fā)現(xiàn):

org.springframework.boot.autoconfigure.web.ServerProperties.Undertow配置地址:

image.png

由此可知:

  1. 服務(wù)器是否開(kāi)啟長(zhǎng)鏈接由alwaysSetKeepAlive控制;
  2. 當(dāng)一個(gè)鏈接noRequestTimeout內(nèi)空閑,服務(wù)器便會(huì)關(guān)閉鏈接;

如代碼所示:

image.png

當(dāng)server的worker在noRequestTimeout空閑時(shí),便會(huì)shutdown該鏈接。于是改鏈接向客戶端發(fā)起FIN配置。

3.3 問(wèn)題解決

也就是設(shè)置noRequestTimeout便可以去解決:服務(wù)器關(guān)閉長(zhǎng)鏈接的問(wèn)題。但是配置文件中未設(shè)置該參數(shù),這個(gè)8s是在哪里來(lái)的?

經(jīng)過(guò)排查發(fā)現(xiàn),配置文件中存在下列配置:

server:
  connection-timeout: 8000

源碼位置:org.springframework.boot.autoconfigure.web.embedded.UndertowWebServerFactoryCustomizer#customize

image.png

也就是設(shè)置了connection-timeout超時(shí)時(shí)間影響了服務(wù)端長(zhǎng)連接關(guān)閉的時(shí)間。

最終解決方案:

server:
  connection-timeout: 60000 # 默認(rèn)60s,此時(shí)顯式的設(shè)置為60s。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容