最新消息:

TCP三次握手-backlog队列问题

Linux ipcpu 8451浏览

TCP三次握手-backlog队列问题.md

概述

之前有同事做压力测试时,发现无论如何都无法突破128并发的问题,经排查发现该服务器ACCEPT QUEUE队列都为128,限制了网络的并发。

TCP三次握手

Linux内核协议栈为一个TCP连接管理使用两个队列,一个是半链接队列SYN QUEUE(用来保存处于SYN_SENT和SYN_RECV状态的请求),一个是ACCEPT队列 ACCEPT QUEUE(用来保存处于established状态,但是应用层没有调用accept取走的请求)。

  1. 当client 建立连接时发送SYN包到server端,server收到之后如果SYN QUEUE队列已满,直接丢弃不回ACK。客户端超时后经过3秒、9秒…的间隔时候不断重发SYN包。

  2. 当server的SYN QUEUE没有满时,server会回复SYN+ACK给client,如果client收到请求,则将状态修改为ESTABLISHED,并发送ACK给server。

  3. 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队列丢弃的数据

  1. [root@nginx2.proxy.qyer.idc ~]#netstat -s | grep "SYNs to LISTEN sockets ignored"
  2. 35552 SYNs to LISTEN sockets ignored
  3. [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命令查看

  1. [root@nginx2.proxy.qyer.idc ~]#ss -ln
  2. State Recv-Q Send-Q Local Address:Port Peer Address:Port
  3. LISTEN 0 100 127.0.0.1:25 *:*
  4. LISTEN 0 128 *:2233 *:*
  5. LISTEN 0 511 *:443 *:*
  6. LISTEN 0 128 10.1.1.2:10050 *:*
  7. LISTEN 0 511 *:80 *:*
  8. [root@nginx2.proxy.qyer.idc ~]#

使用netstat -s 可以查看被ACCEPT QUEUE队列队列丢弃的数据。

  1. [root@nginx2.proxy.qyer.idc ~]#netstat -s | grep "times the listen queue of a socket overflowed"
  2. 35552 times the listen queue of a socket overflowed
  3. [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队列问题