TCP三次握手-backlog队列问题.md
概述
之前有同事做压力测试时,发现无论如何都无法突破128并发的问题,经排查发现该服务器ACCEPT QUEUE队列都为128,限制了网络的并发。
TCP三次握手
Linux内核协议栈为一个TCP连接管理使用两个队列,一个是半链接队列SYN QUEUE(用来保存处于SYN_SENT和SYN_RECV状态的请求),一个是ACCEPT队列 ACCEPT QUEUE(用来保存处于established状态,但是应用层没有调用accept取走的请求)。
-
当client 建立连接时发送SYN包到server端,server收到之后如果SYN QUEUE队列已满,直接丢弃不回ACK。客户端超时后经过3秒、9秒…的间隔时候不断重发SYN包。
-
当server的SYN QUEUE没有满时,server会回复SYN+ACK给client,如果client收到请求,则将状态修改为ESTABLISHED,并发送ACK给server。
-
server收到ACK,将状态修改为ESTABLISHED,并把该请求从SYN QUEUE中放到ACCEPT QUEUE。
SYN QUEUE队列
用于保存半连接状态的请求,其大小通过/proc/sys/net/ipv4/tcp_max_syn_backlog指定。
SYN QUEUE队列长度:tcp_max_syn_backlog
通过netstat -s可以查看被SYN QUEUE队列丢弃的数据
[root@nginx2.proxy.qyer.idc ~]#netstat -s | grep "SYNs to LISTEN sockets ignored"
35552 SYNs to LISTEN sockets ignored
[root@nginx2.proxy.qyer.idc ~]#
ACCEPT QUEUE队列
用于保存全连接状态的请求,其大小通过/proc/sys/net/core/somaxconn(默认是128)指定,在使用listen函数时,内核会根据传入的backlog参数与系统参数somaxconn比较,取二者的较小值。
ACCEPT QUEUE队列长度:min(backlog, somaxconn)
如果accpet queue队列满了,server将如何处理呢?取决于一个参数tcp_aborton_overflow,当tcp_aborton_overflow参数为1,会发送 RST;如果为0(默认值),则直接丢弃报文。
ACCEPT QUEUE队列大小可以使用ss命令查看
[root@nginx2.proxy.qyer.idc ~]#ss -ln
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 128 *:2233 *:*
LISTEN 0 511 *:443 *:*
LISTEN 0 128 10.1.1.2:10050 *:*
LISTEN 0 511 *:80 *:*
[root@nginx2.proxy.qyer.idc ~]#
使用netstat -s 可以查看被ACCEPT QUEUE队列队列丢弃的数据。
[root@nginx2.proxy.qyer.idc ~]#netstat -s | grep "times the listen queue of a socket overflowed"
35552 times the listen queue of a socket overflowed
[root@nginx2.proxy.qyer.idc ~]#
backlog的值不宜过大,nginx和redis都是使用的511。PHP曾出现将此数值改为65535又改回来的情况。详情可以参考这篇文章:
http://www.cnxct.com/something-about-phpfpm-s-backlog/
两个队列大小不一致
很明显,从上面举例来看,两个队列大小在很多情况下是不一致的。
ACCEPT队列大多数情况下会比较小,所以会出现SYN QUEUE没有满,而ACCEPT QUEUE满了的情况,此时会按照tcp_aborton_overflow来决定直接丢弃,还是返回拒绝RST。
而如果启用了syncookies,那么syncookies会开启,限制SYN包进入的速度。
SYN COOKIE问题
为了应对SYNflooding(即客户端只发送SYN包发起握手而不回应ACK完成连接建立,填满server端的半连接队列,让它无法处理正常的握手请求),Linux实现了一种称为SYNcookie的机制,通过net.ipv4.tcp_syncookies控制,设置为1表示开启。
简单说SYNcookie就是将连接信息编码在ISN(initialsequencenumber)中返回给客户端,这时server不需要将半连接保存在队列中,而是利用客户端随后发来的ACK带回的ISN还原连接信息,以完成连接的建立,避免了半连接队列被攻击SYN包填满。
当开启syn cookie以后,一旦半连接队列(SYN QUEUE)满了系统就会启用syn cookie功能,同时在/var/log/messages记录kernel: possible SYN flooding on port 80. Sending cookies。
但此时队列的大小并不是tcp_max_syn_backlog设置的值,而是由以下3个参数最小值决定。
SYN QUEUE队列长度=min(backlog,net.core.somaxconn,tcp_max_syn_backlog)。
.
参考资料
http://mp.weixin.qq.com/s?__biz=MjM5NzUwNDA5MA==&mid=201005717&idx=1&sn=74036633114ee6212e57ee4576dbfcbc&3rd=MzA3MDU4NTYzMw==&scene=6#rd
http://gmd20.blog.163.com/blog/static/16843923201471310322880/
http://jaseywang.me/2014/07/20/tcp-queue-%E7%9A%84%E4%B8%80%E4%BA%9B%E9%97%AE%E9%A2%98/
http://www.slideshare.net/jooholee81/tcp-summary
http://www.cnxct.com/something-about-phpfpm-s-backlog/
http://blog.dujiong.net/2016/09/28/tcp-backlog/
http://www.jameswxx.com/%E7%B3%BB%E7%BB%9F%E5%9F%BA%E7%A1%80/%E5%85%B3%E4%BA%8Ebacklog/
https://yq.aliyun.com/articles/4252
转载请注明:IPCPU-网络之路 » TCP三次握手-backlog队列问题