目錄
三次握手
- 第一次握手:客戶端發送syn包(syn=j)到服務器,並進入SYN_SEND狀態,等待服務器確認;
(將連接放入半連接隊列中)
- 第二次握手:服務器收到syn包,必須確認客戶的SYN(ack=j+1),同時也發送一個SYN包(syn=k),即SYN+ACK包,此時服務器進入SYN_RECV狀態;
- 第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=k+1),此包發送完畢,客戶端和服務器進入ESTABLISHED狀態,完成三次握手。
(連接從半連接隊列移出,移入全連接隊列中。)
當服務端端調用accept()時,會將連接從全連接隊列中取出。
半連接隊列和全連接隊列的大小
syns queue大小
max(64,/proc/sys/net/ipv4/tcp_max_syn_backlog)
accept queue大小
accept queue大小取決於:min(backlog,somaxconn),
-
backlog由listen()函數的backlog決定
thrift中默認的backlog大小為1024
-
somaxconn則是內核參數:/proc/sys/net/core/somaxconn
somaxconn默認為128
查看全連接隊列大小
ss -lnt 'sport=:10240'
Stae Recv-Q Send-Q Local Address:port
LISTEN 0 128 *:10240
Send-Q:全連接隊列(accept queue)的最大值,其值為min(backlog,somaxconn)
Recv-Q:已建立成功(狀態為ESTABLISHED),但尚未交付給應用的“tcp連接的數量”,其最大值為Send-Q+1。(即三次握手完成,但是服務端還沒有調用accept從全連接中取出的連接數量----積壓數量)
netstat -anp |grep 10240
accept queue隊列滿之后協議棧的處理策略
cat /proc/sys/net/ipv4/tcp_abort_on_overflow
#有效值為:0或1
- 0:當tcp建立連接的3次握手完成后,將連接置為ESTABLISHED狀態並交付給應用程序的backlog隊列時,會檢查backlog隊列是否已滿。若已滿,通常行為是將連接還原至SYN_ACK狀態,以造成3次握手最后的ACK包意外丟失的假象,這樣在客戶端等待超時后可重發ACK,以再次嘗試進入ESTABLISHED狀態,作為一種修復、重試機制。
- 1:如果tcp_abort_on_overflow為1,則在檢查到backlog隊列已滿時,直接發RST包給客戶端終止此連接。此時客戶端程序會收到104 Connection reset by peer錯誤。
全連接隊列、半連接隊列溢出的問題很容易被忽略,但是又很關鍵,特別是對於一些短連接應用更容易爆發。一旦溢出,從CPU、線程狀態看都正常,但是壓力上不去。
如何定位客戶端異常與連接隊列滿有關
為了證明客戶端應用程序異常跟全連接隊列滿有關系,可以先把tcp_abort_on_overflow參數修改為1,接着測試如果在客戶端異常中可以看到很多connection reset by peer錯誤,說明客戶端錯誤是連接隊列滿導致的。
或者
netstat -s|grep "listen|LISTEN"
3 times the listen queue of a socket overflowed
s SYNs to LISTEN sockets dropped
說明發生了3次全連接隊列溢出。