TCP
2025-08-22 12:50:17 1 举报
AI智能生成
无
作者其他创作
大纲/内容
全队列和半队列
半连接队列,也称 SYN 队列;.
全连接队列,也称 accept 队列;
服务端收到客户端发起的 SYN 请求后,内核会把该连接存储到半连接队列,并向客户端响应 SYN+ACK接着客户端会返回 ACK,服务端收到第三次握手的 ACK后,内核会把连接从半连接队列移除,然后创建新的完全的连接,并将其添加到 accept 队列,等待进程调用 accept 函数时把连接取出来。
全连接队列,也称 accept 队列;
服务端收到客户端发起的 SYN 请求后,内核会把该连接存储到半连接队列,并向客户端响应 SYN+ACK接着客户端会返回 ACK,服务端收到第三次握手的 ACK后,内核会把连接从半连接队列移除,然后创建新的完全的连接,并将其添加到 accept 队列,等待进程调用 accept 函数时把连接取出来。
TCP全连接队列的溢出
查看命令:在服务端可以使用ss命令,来查看 TCP 全连接队列的情况。
查看命令:在服务端可以使用ss命令,来查看 TCP 全连接队列的情况
从上面的模拟结果,可以得知,当服务端并发处理大量请求时,如果 TCP 全连接队列过小,就容易溢出。发生 TCP 全连接队溢出的时候,后续的请求就会被丢弃,这样就会出现服务端请求数量上不去的现象。
tcp_abort_on_overflow 共有两个值分别是0和1,其分别表示:
0:如果全连接队列满了,那么 server 扔掉 client 发过来的 ack;
1:如果全连接队列满了,server 发送一个 reset 包给 client,表示废掉这个握手过程和这个连接;
0:如果全连接队列满了,那么 server 扔掉 client 发过来的 ack;
1:如果全连接队列满了,server 发送一个 reset 包给 client,表示废掉这个握手过程和这个连接;
通常情况下,应当把 tcp abort on overflow 设置为 0,因为这样更有利于应对突发流量。
举个例子,当 TCP 全连接队列满导致服务器丢掉了 ACK,与此同时,客户端的连接状态却是ESTABLISHED,进程就在建立好的连接上发送请求。只要服务器没有为请求回复 ACK,请求就会被多次重发。如果服务器上的进程只是短暂的繁忙造成 accept 队列满,那么当 TCP 全连接队列有空位时,再次接收到的请求报文由于含有 ACK,仍然会触发服务器端成功建立连接。
举个例子,当 TCP 全连接队列满导致服务器丢掉了 ACK,与此同时,客户端的连接状态却是ESTABLISHED,进程就在建立好的连接上发送请求。只要服务器没有为请求回复 ACK,请求就会被多次重发。如果服务器上的进程只是短暂的繁忙造成 accept 队列满,那么当 TCP 全连接队列有空位时,再次接收到的请求报文由于含有 ACK,仍然会触发服务器端成功建立连接。
tcp_abort_on_overflow 设为0可以提高连接建立的成功率,只有你非常肯定 TCP 全连接队列会长期溢出时,才能设置为1以尽快通知客户端。
增大全连接队列的大小
TCP 全连接队列的最大值取决于 somaxconn 和 backlog 之间的最小值,也就是 min(somaxconn,backlog)
somaxconn是 Linux 内核的参数,默认值是 128,可以通过 /proc/sys/net/core/somaxconn来设置其值;
backlog是 listen(int sockfd,int backlog)函数中的 backlog 大小,Nginx 默认值是 511,可以通过修改配置文件设置其长度;
backlog是 listen(int sockfd,int backlog)函数中的 backlog 大小,Nginx 默认值是 511,可以通过修改配置文件设置其长度;
半连接队列溢出
查看服务端处于SYN_RECV状态的TCP连接,就是TCO半连接队列。
模拟 TCP 半连接溢出场景不难,实际上就是对服务端一直发送 TCP SYN 包,但是不回第三次握手ACK这样就会使得服务端有大量的处于SYN_RECV 状态的 TCP 连接。
这其实也就是所谓的 SYN 洪泛、SYN 攻击、DDos 攻击。
这其实也就是所谓的 SYN 洪泛、SYN 攻击、DDos 攻击。
溢出处理逻辑
1、如果半连接队列满了,并且没有开启 tcp_syncookies,则会丢弃;
2、若全连接队列满了,且没有重传 SYN+ACK 包的连接请求多于1个,则会丢弃;
3、如果没有开启 tcp_syncookies,并且 max_syn backlog 减去 当前半连接队列长度小于 (max_syn_backlog >>2),则会丢弃
2、若全连接队列满了,且没有重传 SYN+ACK 包的连接请求多于1个,则会丢弃;
3、如果没有开启 tcp_syncookies,并且 max_syn backlog 减去 当前半连接队列长度小于 (max_syn_backlog >>2),则会丢弃
半连接队列的最大值由什么决定?
半连接队列的最大值是max_qlen_log变量
当 max_syn_backlog >min(somaxconn, backlog) 时,半连接队列最大值 max_qlen log =min(somaxconn, backlog)* 2;
当 max_syn_backlog<min(somaxconn, backlog) 时,半连接队列最大值 max_qlen_log =max_syn backlog * 2;
当 max_syn_backlog<min(somaxconn, backlog) 时,半连接队列最大值 max_qlen_log =max_syn backlog * 2;
所以,服务端处于 SYN_RECV 状态的最大个数分为如下两种情况:
如果「当前半连接队列」没超过「理论半连接队列最大值」,但是超过 max_syn backlog-(max_syn_backlog >>2),那么处于 SYN_RECV 状态的最大个数就是 max_syn_backlog-(max_syn backlog >>2)
如果「当前半连接队列」超过「理论半连接队列最大值」,那么处于 SYN RECV 状态的最大个数就是「理论半连接队列最大值」;
如果「当前半连接队列」没超过「理论半连接队列最大值」,但是超过 max_syn backlog-(max_syn_backlog >>2),那么处于 SYN_RECV 状态的最大个数就是 max_syn_backlog-(max_syn backlog >>2)
如果「当前半连接队列」超过「理论半连接队列最大值」,那么处于 SYN RECV 状态的最大个数就是「理论半连接队列最大值」;
半连接队列已满,不一定要丢弃连接
并不是这样,开启 syncookies 功能就可以在不使用 SYN 半连接队列的情况下成功建立连接,在前面我们源码分析也可以看到这点,当开启了 syncookies 功能就不会丢弃连接。
syncookies 是这么做的:服务器根据当前状态计算出一个值,放在己方发出的 SYN+ACK 报文中发出,当客户端返回 ACK 报文时,取出该值验证,如果合法,就认为连接建立成功,如下图所示。
syncookies 是这么做的:服务器根据当前状态计算出一个值,放在己方发出的 SYN+ACK 报文中发出,当客户端返回 ACK 报文时,取出该值验证,如果合法,就认为连接建立成功,如下图所示。
syncookies 参数主要有以下三个值:
·0值,表示关闭该功能;
·1值,表示仅当 SYN 半连接队列放不下时,再启用它,
·2值,表示无条件开启功能
那么在应对 SYN 攻击时,只需要设置为 1 即可:
·0值,表示关闭该功能;
·1值,表示仅当 SYN 半连接队列放不下时,再启用它,
·2值,表示无条件开启功能
那么在应对 SYN 攻击时,只需要设置为 1 即可:
预防SYN攻击
1、增大半连接队列
在前面源码和实验中,得知要想增大半连接队列,我们得知不能只单纯增大 tcp_max_syn_backlog 的值还需一同增大 somaxconn 和 backlog,也就是增大全连接队列。否则,只单纯增大tcp_max_syn_backlog是无效的。
2、开启tcp-syncookies功能
3、减少SYN+ACK重传次数
当服务端受到 SYN 攻击时,就会有大量处于 SYN RECV 状态的 TCP 连接,处于这个状态的 TCP 会重传SYN+ACK,当重传超过次数达到上限后,就会断开连接。
那么针对 SYN 攻击的场景,我们可以减少 SYN+ACK 的重传次数,以加快处于 SYN RECV 状态的 TCP 连接断开。
那么针对 SYN 攻击的场景,我们可以减少 SYN+ACK 的重传次数,以加快处于 SYN RECV 状态的 TCP 连接断开。
Main Topic
Subtopic
Subtopic
Main Topic
Subtopic
Subtopic
0 条评论
下一页