Linux TCP RST情況
導讀 | 導致“Connection reset”的原因是伺服器端因為某種原因關閉了Connection,而客戶端依然在讀寫資料,此時伺服器會返回復位標誌“RST”,然後此時客戶端就會提示“java.net.SocketException: Connection reset”。可能有同學對復位標誌“RST”還不太瞭解,這裡簡單解釋一下: |
TCP建立連線時需要三次握手,在釋放連線需要四次揮手;例如三次握手的過程如下:
第一次握手:客戶端傳送syn包(syn=j)到伺服器,並進入SYN_SENT狀態,等待伺服器確認;
第二次握手:伺服器收到syn包,並會確認客戶的SYN(ack=j+1),同時自己也傳送一個SYN包(syn=k),即SYN+ACK包,此時伺服器進入SYN_RECV狀態;
第三次握手:客戶端收到伺服器的SYN+ACK包,向伺服器傳送確認包ACK(ack=k+1),此包傳送完畢,客戶端和伺服器進入ESTABLISHED(TCP連線成功)狀態,完成三次握手。
可以看到握手時會在客戶端和伺服器之間傳遞一些TCP頭資訊,比如ACK標誌、SYN標誌以及揮手時的FIN標誌等。
除了以上這些常見的標誌頭資訊,還有另外一些標誌頭資訊,比如推標誌PSH、復位標誌RST等。其中復位標誌RST的作用就是“復位相應的TCP連線”。
TCP連線和釋放時還有許多細節,比如半連線狀態、半關閉狀態等。詳情請參考這方面的鉅著《TCP/IP詳解》和《UNIX網路程式設計》。
前面說到出現“Connection reset”的原因是伺服器關閉了Connection[呼叫了Socket.close()方法]。大家可能有疑問了:伺服器關閉了Connection為什麼會返回“RST”而不是返回“FIN”標誌。原因在於Socket.close()方法的語義和TCP的“FIN”標誌語義不一樣:傳送TCP的“FIN”標誌表示我不再傳送資料了,而Socket.close()表示我不在傳送也不接受資料了。問題就出在“我不接受資料” 上,如果此時客戶端還往伺服器傳送資料,伺服器核心接收到資料,但是發現此時Socket已經close了,則會返回“RST”標誌給客戶端。當然,此時客戶端就會提示:“Connection reset”。詳細說明可以參考oracle的有關文件:http://docs.oracle.com/javase/1.5.0/docs/guide/net/articles/connection_release.html。
另一個可能導致的“Connection reset”的原因是伺服器設定了Socket.setLinger (true, 0)。但我檢查過線上的tomcat配置,是沒有使用該設定的,而且線上的伺服器都使用了nginx進行反向代理,所以並不是該原因導致的。關於該原因上面的oracle文件也談到了並給出瞭解釋。
此外囉嗦一下,另外還有一種比較常見的錯誤“Connection reset by peer”,該錯誤和“Connection reset”是有區別的:
伺服器返回了“RST”時,如果此時客戶端正在從Socket套接字的輸出流中讀資料則會提示Connection reset”;
伺服器返回了“RST”時,如果此時客戶端正在往Socket套接字的輸入流中寫資料則會提示“Connection reset by peer”。
“Connection reset by peer”如下圖所示:
前面談到了導致“Connection reset”的原因,而具體的解決方案有如下幾種:
出錯了重試;
客戶端和伺服器統一使用TCP長連線;
客戶端和伺服器統一使用TCP短連線。
首先是出錯了重試:這種方案可以簡單防止“Connection reset”錯誤,然後如果服務不是“冪等”的則不能使用該方法;比如提交訂單操作就不是冪等的,如果使用重試則可能造成重複提單。
然後是客戶端和伺服器統一使用TCP長連線:客戶端使用TCP長連線很容易配置(直接設定HttpClient就好),而伺服器配置長連線就比較麻煩了,就拿tomcat來說,需要設定tomcat的maxKeepAliveRequests、connectionTimeout等引數。另外如果使用了nginx進行反向代理或負載均衡,此時也需要配置nginx以支援長連線(nginx預設是對客戶端使用長連線,對伺服器使用短連線)。
使用長連線可以避免每次建立TCP連線的三次握手而節約一定的時間,但是我這邊由於是內網,客戶端和伺服器的3次握手很快,大約只需1ms。ping一下大約0.93ms(一次往返);三次握手也是一次往返(第三次握手不用返回)。根據80/20原理,1ms可以忽略不計;又考慮到長連線的擴充套件性不如短連線好、修改nginx和tomcat的配置代價很大(所有後臺服務都需要修改);所以這裡並沒有使用長連線。
正常情況tcp四層握手關閉連線,rst基本都是異常情況,整理如下:
0.使用 ping 可以看到丟包情況
如果對方sync_backlog滿了的話,sync簡單被丟棄,表現為超時,而不會rst[/yiji]
例如,客戶端發了兩個請求,伺服器只從buffer 讀取第一個請求處理完就關閉連線,tcp層認為資料沒有正確提交到應用,使用rst關閉連線。
行動網路下,國內是有5分鐘後就回收信令,也就是IM產品,如果心跳>5分鐘後伺服器再給客戶端發訊息,就會收到rst。也要查行動網路下IM 保持<5min 心跳。
負載裝置需要維護連線轉發策略,長時間無流量,連線也會被清除,而且很多都不告訴兩層機器,新的包過來時才通告rst。
Apple push 服務也有這個問題,而且是不可預期的偶發性連線被rst;rst 前第一個訊息write 是成功的,而第二條寫才會告訴你連線被重置,
曾經被它折騰沒轍,因此開啟每2秒一次tcp keepalive,固定5分鐘tcp連線回收,而且發現連線出錯時,重發之前10s內訊息。
該選項會直接丟棄未傳送完畢的send buffer,可能造成業務錯誤,慎用; 當然內網服務間http client 在收到應該時主動關閉,使用改選項,會節省資源。
好像曾經測試過haproxy 某種配置下,會使用rst關閉連線,少了網路互動而且沒有TIME_WAIT 問題
tw_recycle = 1 時,sync timestamps 比上次小時,會被rst[/yiji]
應用設定了連線超時,sync 未完成時超時了,會傳送rst終止連線。[/yiji]
連線已經關閉,seq 不正確等
公網服務tcp keepalive 最好別開啟;行動網路下會增加網路負擔,切容易掉線;非行動網路核心ISP裝置也不一定都支援keepalive,曾經也發現過廣州那邊有個核心節點就不支援。
客戶端沒有收到伺服器的關閉請求,這稱為TCP半開啟連線。就算重啟伺服器,也沒有連線資訊。如果客戶端向提其寫入資料,對方就會回應一個RST報文段。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2731408/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Linux 檢視程式情況Linux
- 從TCP協議的原理論rst復位攻擊TCP協議
- linux 防火牆埠號開發情況Linux防火牆
- linux系統檢視網路連線情況Linux
- 如何快速檢視Linux系統重啟情況Linux
- 什麼情況下不應該使用 Windows Linux 子系統WindowsLinux
- jstat命令檢視jvm的GC情況 (以Linux為例)JSJVMGCLinux
- Linux中什麼情況下會發生程式排程?Linux
- Linux檔案或目錄顏色一般情況Linux
- 【譯】TCP Implementation in LinuxTCPLinux
- metricbeat 監控 nginx 情況Nginx
- switch不加break情況分析
- mysql索引失效的情況MySql索引
- 城市天氣情況APIAPI
- 成都現在的情況
- 05記憶體情況記憶體
- NoClassDefFoundError的兩種情況Error
- [20200219]strace跟蹤設定ENABLE=BROKEN的情況(網路的情況).txt
- Linux TCP通訊示例LinuxTCP
- 在不重啟的情況下為 Vmware Linux 客戶機新增新硬碟Linux硬碟
- DOM對映的特殊情況
- MySQL哪些情況需要新增索引?MySql索引
- appium2.0 目前啥情況APP
- 【Linux學習教程】Linux中tcp與tcp6區別是什麼?LinuxTCP
- linux 網路 cat /proc/net/dev 檢視測試網路丟包情況Linuxdev
- 使用 Ledger 記錄(財務)情況
- 多種情況解析深複製
- long long的加法溢位情況
- String不同定義的情況解析
- PLinq不需要鎖的情況
- ubuntu檢視硬碟掛載情況Ubuntu硬碟
- oracle order by索引是否使用的情況Oracle索引
- mysql索引不會命中的情況MySql索引
- js中this指向有幾種情況JS
- 什麼情況下不能使用最壞情況評估演算法的複雜度?演算法複雜度
- Linux學習/TCP Socket通訊LinuxTCP
- 線性時間選擇(含平均情況O(n)和最壞情況O(n)演算法)演算法
- Linux 系統存在 inode 號被用完但磁碟空間還有剩餘的情況Linux