當前位置:編程學習大全網 - 源碼下載 - Netty 出現 Connection reset by peer 異常的幾個原因

Netty 出現 Connection reset by peer 異常的幾個原因

最近使用 netty 過程中發現了幾個比較細節的 Connection reset by peer 異常,做個筆記。

這個場景出現在用 Jedis ping 檢測的場景,用完直接 close,服務端穩定出現 Connection reset by peer。

tcpdump 壹下就很容易定位到問題所在,客戶端收到 PONG 響應後直接發了壹個 RST 包給服務端:

查看 Jedis 的源碼發現 socket 有個比較特殊的配置 socket.setSoLinger(true, 0) 。

先看壹下 man7/socket.7 的解釋:

坦白說不是很明白啥意思。。。

最終在 stackoverflow 上找到壹個比較容易理解的解釋:

簡而言之,設置 SO_LINGER(0) 可以不進行四次揮手直接關閉 TCP 連接,在協議交互上就是直接發 RST 包,這樣的好處是可以避免長時間處於 TIME_WAIT 狀態,當然 TIME_WAIT 存在也是有原因的,大部分評論都不建議這樣配置。

這個場景有點兒微妙,首先得理解壹下 tcp 的兩個隊列。

這篇文章講得比較清楚: SYN packet handling in the wild

accept 隊列滿通常是由於 netty boss 線程處理慢,特別是在容器化之後,服務剛啟動的時候很容易出現 CPU 受限。

為了模擬這個現象,我寫了個示例程序 shichaoyuan/netty-backlog-test ,設置 SO_BACKLOG 為 1,並且在 accept 第壹個連接後設置 autoRead 為 false,也就是讓 boss 線程不再繼續 accept 連接。

啟動第壹個 Client,可以正常連接,發送 PING,接收 PONG。

啟動第二個 Client,也可以正常連接,但是沒有收到 PONG:

可見這個連接創建成功了,已經在 Accept Queue 裏了,但是進程沒有 accept,所以沒有與進程綁定。

啟動第三個 Client,也可以正常連接,也沒有收到 PONG:

與第二個連接壹樣。

啟動第四個 Client,也可以正常連接,但是在發送 PING 後出現 Connection reset by peer:

這個連接在服務端並沒有進入 accept queue,處於 SYN_RECV 狀態,並且很快就消失了(因為 accept queue 已經滿了,無法轉入 ESTABLISHED 狀態)。

抓包看壹下:

從客戶端視角來看連接確實是建成功了,有壹個比較特殊的地方在三次握手之後,服務端又向客戶端發送了壹個 [S.],客戶端回復了壹個 [.],這個交互看起來不影響連接。

服務端後來銷毀了連接,而客戶端還認為連接是 ESTABLISHED 的,發送 PING 消息,服務端自然得回復壹個 RST。

PS:我在 Windows 10 的 WSL2 中實驗這種場景是建連接超時,可能不同的操作系統或 linux 版本對這個交互的過程處理不同,在此不進行進壹步測試了。

以上,這個故事告訴我們判斷連接是否可用,建成功之後應該發個心跳包測試壹下。

  • 上一篇:日系動畫片裏主角在變身的時候,敵人為啥沒動靜?
  • 下一篇:成員管理源代碼java
  • copyright 2024編程學習大全網