连接|TCP半连接队列和全连接队列满了,怎么破( 二 )


实际上,丢弃连接只是Linux的默认行为,我们还可以选择向客户端发送RST复位报文,告诉客户端连接已经建立失败。
tcp_abort_on_overflow共有两个值分别是0和1,其分别表示:
0:表示如果全连接队列满了,那么server扔掉client发过来的ack;
1:表示如果全连接队列满了,那么server发送一个reset包给client,表示废掉这个握手过程和这个连接;
如果要想知道客户端连接不上服务端,是不是服务端TCP全连接队列满的原因,那么可以把tcp_abort_on_overflow设置为1,这时如果在客户端异常中可以看到很多connectionresetbypeer的错误,那么就可以证明是由于服务端TCP全连接队列溢出的问题。
通常情况下,应当把tcp_abort_on_overflow设置为0,因为这样更有利于应对突发流量。
举个例子,当TCP全连接队列满导致服务器丢掉了ACK,与此同时,客户端的连接状态却是ESTABLISHED,进程就在建立好的连接上发送请求。只要服务器没有为请求回复ACK,请求就会被多次重发。如果服务器上的进程只是短暂的繁忙造成accept队列满,那么当TCP全连接队列有空位时,再次接收到的请求报文由于含有ACK,仍然会触发服务器端成功建立连接。
所以,tcp_abort_on_overflow设为0可以提高连接建立的成功率,只有你非常肯定TCP全连接队列会长期溢出时,才能设置为1以尽快通知客户端。
4、如何增大TCP全连接队列呢?
是的,当发现TCP全连接队列发生溢出的时候,我们就需要增大该队列的大小,以便可以应对客户端大量的请求。
TCP全连接队列足最大值取决于somaxconn和backlog之间的最小值,也就是min(somaxconn,backlog)。从下面的Linux内核代码可以得知:

 连接|TCP半连接队列和全连接队列满了,怎么破
文章图片

somaxconn是Linux内核的参数,默认值是128,可以通过/proc/sys/net/core/somaxconn来设置其值;backlog是listen(intsockfd,intbacklog)函数中的backlog大小,Nginx默认值是511,可以通过修改配置文件设置其长度;
前面模拟测试中,我的测试环境:
somaxconn是默认值128;
Nginx的backlog是默认值511
所以测试环境的TCP全连接队列最大值为min(128,511),也就是128,可以执行ss命令查看:
现在我们重新压测,把TCP全连接队列搞大,把somaxconn设置成5000:
接着把Nginx的backlog也同样设置成5000:

 连接|TCP半连接队列和全连接队列满了,怎么破
文章图片

最后要重启Nginx服务,因为只有重新调用listen()函数,TCP全连接队列才会重新初始化。重启完后Nginx服务后,服务端执行ss命令,查看TCP全连接队列大小:
从执行结果,可以发现TCP全连接最大值为5000。
5、增大TCP全连接队列后,继续压测
客户端同样以3万个连接并发发送请求给服务端:

 连接|TCP半连接队列和全连接队列满了,怎么破
文章图片

服务端执行ss命令,查看TCP全连接队列使用情况:
 连接|TCP半连接队列和全连接队列满了,怎么破
文章图片

从上面的执行结果,可以发现全连接队列使用增长的很快,但是一直都没有超过最大值,所以就不会溢出,那么netstat-s就不会有TCP全连接队列溢出个数的显示:说明TCP全连接队列最大值从128增大到5000后,服务端抗住了3万连接并发请求,也没有发生全连接队列溢出的现象了。
如果持续不断地有连接因为TCP全连接队列溢出被丢弃,就应该调大backlog以及somaxconn参数。
实战-TCP半连接队列溢出
1、如何查看TCP半连接队列长度?
很遗憾,TCP半连接队列长度的长度,没有像全连接队列那样可以用ss命令查看。
但是我们可以抓住TCP半连接的特点,就是服务端处于SYN_RECV状态的TCP连接,就是在TCP半连接队列。
于是,我们可以使用如下命令计算当前TCP半连接队列长度:

 连接|TCP半连接队列和全连接队列满了,怎么破
文章图片

2、如何模拟TCP半连接队列溢出场景?模拟TCP半连接溢出场景不难,实际上就是对服务端一直发送TCPSYN包,但是不回第三次握手ACK,这样就会使得服务端有大量的处于SYN_RECV状态的TCP连接。
这其实也就是所谓的SYN洪泛、SYN攻击、DDos攻击。

 连接|TCP半连接队列和全连接队列满了,怎么破
文章图片

测试环境实验环境:
客户端和服务端都是CentOs6.5,Linux内核版本2.6.32
服务端IP192.168.3.200,客户端IP192.168.3.100
服务端是Nginx服务,端口为8088
注意:本次模拟实验是没有开启tcp_syncookies,关于tcp_syncookies的作用,后续会说明。
本次实验使用hping3工具模拟SYN攻击:

 连接|TCP半连接队列和全连接队列满了,怎么破


推荐阅读