最新消息:

TCP三次握手-backlog队列问题

backlog admin 3008浏览 0评论

概述

之前有同事做压力测试时,发现无论如何都无法突破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队列丢弃的数据

[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)。

.

参考资料

TCP queue 的一些问题

关于tcp listen queue的一点事

Linux TCP队列相关参数的总结

TCP SOCKET中backlog参数的用途是什么?

TCP洪水攻击(SYN Flood)的诊断和处理

转载请注明:爱开源 » TCP三次握手-backlog队列问题

您必须 登录 才能发表评论!