雲架構那些事兒:為什麼我的TCP連接建立異常?

雲架構那些事兒:為什麼我的TCP連接建立異常?

搞IT的同學無論是做開發的、做測試的、做運維的一定都遇到過以下幾種報錯,導致服務調用失敗:

connection timeout

read timeout

connection reset by peer

都是服務調用失敗,但是有3種報錯信息,到底有什麼差別呢?

本文將給大家分享以上錯誤異常出現的一種可能性,希望對你理解TCP連接、解決系統問題有所幫助。

首先我們來看一下正常的TCP連接交互:

雲架構那些事兒:為什麼我的TCP連接建立異常?

正常通信場景

如果你對TCP建立連接三次握手的流程可能有所瞭解,那麼你對SYN,SYN-ACK,ACK,SYN_SENT,SYN_RECV,ESTABLISH一定並不陌生,但其中SYN Queue和Accept Queue你可能沒有見過。這正是本文要講的重點。

SYN Queue:接收TCP SYN連接的隊列,由操作系統參數 tcp_max_syn_backlog 控制,如果處於SYN_RECV的數量超過tcp_max_syn_backlog的值,則操作系統將直接拋棄客戶端發出的SYN。

客戶端由於未收到服務端返回的SYN-ACK,將在客戶端配置的系統參數tcp_syn_retries次數後,放棄建立該TCP鏈接,客戶端側的報錯即:connection timeout

過程如下:

雲架構那些事兒:為什麼我的TCP連接建立異常?

SYN Queue滿的場景

Accept Queue:在完成SYN,SYN-ACK,ACK後,連接將進入accept queue,直到服務端將調用accept()後即開始正常處理後續的數據包請求。該值將在操作系統的somaxconn參數及該應用程序自身的backlog參數最小值決定,即min(somaxconn,backlog),請注意,這裡的backlog並不是操作系統參數 tcp_max_syn_backlog。

如果Accept Queue由於應用程序性能不足或配置不當導致用滿了,則根據操作系統參數tcp_abort_on_overflow來進行處理,下圖為tcp_abort_on_overflow為默認值0時的返回情況,即操作系統將直接拋棄ACK,相當於服務端沒有收到該ACK,但客戶端會並不知道,認為三次握手已經完成,所以會發送業務數據包PSH,ACK,可惜的是從服務端的角度看,三次握手其實並沒有真正完成,且由於最後一次握手的ACK相當於沒有收到,因此會再次發送SYN-ACK給客戶端(發送次數由tcp_synack_retries決定)。客戶端將再次發送第三次握手的ACK給服務端,多次嘗試後,客戶端超時,將報錯:read timeout。

雲架構那些事兒:為什麼我的TCP連接建立異常?

Accept Queue滿的場景1

如果Accept Queue滿了,且系統參數tcp_abort_on_overflow=1,則操作系統將直接返回RST給客戶端,客戶端將報錯:connection reset by peer。

雲架構那些事兒:為什麼我的TCP連接建立異常?

Accept Queue滿的場景2

查看端口的accept queue隊列最大值:

ss -nlt

找到對應服務端口的Send-Q列值,即accept queue隊列的最大值。

查看端口的accept queue隊列當前值:

ss -tonp

找到對應服務端口的Send-Q列值,即accept queue隊列的當前值。

總結:

對於小併發的場景,類似報錯基本上都是服務端應用程序自身問題,導致的沒有辦法及時處理連接/業務請求。

對於高併發的場景,如果應用程序自身並不是瓶頸,就要考慮增加參數看是否可以避免這些問題了,

如增加系統參數 tcp_max_syn_backlog 的值來讓系統可以同時接受更多SYN連接;

增加系統參數 somaxconn 的值增加accept隊列的長度,當然同時要考慮增加應用的backlog參數,這裡列三個比較常用的應用backlog設置方法

Tomcat:server.xml acceptcount=100

Redis:redis.conf tcp-backlog 511

Nginx:listen backlog=511


分享到:


相關文章: