全连接队列和半连接队列

  • A+
所属分类:linux技术
摘要

当服务端端调用accept()时,会将连接从全连接队列中取出。max(64,/proc/sys/net/ipv4/tcp_max_syn_backlog)

三次握手

全连接队列和半连接队列

  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次全连接队列溢出。