全連接隊列和半連接隊列


三次握手

  1. 第一次握手:客戶端發送syn包(syn=j)到服務器,並進入SYN_SEND狀態,等待服務器確認;(將連接放入半連接隊列中)
  2. 第二次握手:服務器收到syn包,必須確認客戶的SYN(ack=j+1),同時也發送一個SYN包(syn=k),即SYN+ACK包,此時服務器進入SYN_RECV狀態;
  3. 第三次握手:客戶端收到服務器的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次全連接隊列溢出。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM