TCP backlog 队列设计初衷是为了缓存服务器无法立即处理的握手请求先回顾一下三次握手的过程:
图片来源于网络,侵删
从服务器的视角来看,需要接受两个数据包(首个SYN,最后一个ACK)TCP backlog创建了两个队列来负责缓存已经收到的首个SYN和已经握手完成待应用层接收的连接负责缓存SYN的队列叫SYN QUEUE负责缓存已完成连接叫ACCEPT QUEUE
举例子来说明:如果坐火车来说明的话,在春运时,火车站人满为患,进入火车站分为两步:
- 进入候车室(SYN QUEUE)
- 进入站台 (ACCEPT QUEUE)(握手完成)
- 坐上火车 (连接被应用程序使用)
一、进入候车室入SYN QUEUE队列:SYN QUEUE队列的长度可以理解为候车室的大小专业术语叫做BACKLOG,当一个新的旅客到达时,安检员会根据候车室人数来决定是否允许旅客进入
二、登上站台出SYN QUEUE队列,进入ACCEPT QUEUE队列:当站台可以容纳旅客的时候,检票员会将候车室的旅客按照先来后到的顺序,将旅客安置在站台,等候火车的到来,此时验证已经完成(你的车票已经被剪了),TCP已经完成的他的使命
三、挤进火车出ACCEPT QUEUE队列,当乘务员终于慢悠悠的打开车厢大门的时候,所有旅客有序进入火车中,握手完成
QA
如何设置SYN QUEUE和ACCEPT QUEUE的大小?
查看当前的配置:
# syn queue
root@XXX:~# sysctl -a | grep net.ipv4.tcp_max_syn_backlog
net.ipv4.tcp_max_syn_backlog = 256
# accept queue
# 全连接队列的大小通过/proc/sys/net/core/somaxconn指定
# 在使用listen函数时,内核会根据传入的backlog参数与系统参数somaxconn
# 默认选择较小的一方
root@XXX:~# sysctl -a | grep net.core.somaxconn
net.core.somaxconn = 128
变更配置vim /etc/sysctl.conf
net.ipv4.tcp_max_syn_backlog=256
net.core.somaxconn=256
生效命令: sysctl -p
如果队列满了的话TCP会如何处理?
如果连接队列没有空间时,tcp会选择直接丢弃请求报文,这是一种非常巧妙的作法,请求端可能认为是网络丢包所以未收到响应,所以请求端会超时重传,这么做只影响握手成功的时间
这种情况能导致的现象是:A先于B向服务器C发起握手请求,但实际上由于重试的原因,最终可能是B先握手成功。
队列设置太长或者太短,会有什么影响?
如果设置太长,导致迟迟得不到处理,同样会触发客户端的超时重传,并且会浪费内存
如果设置过短,会导致触发大量的TCP重传,导致网络带宽的拥塞
什么情况下需要增加或者减少队列长度?
增加:
1. 请求连接的请求速率很大,且服务的性能足够好,SYN\ACCEPT队列都应该设置大一些
2. 与客户端的RTT时间较长时,可以适当增加
减少:
1. 队列末尾的数据包的响应时间,超过的tcp重传时间时2. 常常遭受syn flood攻击时,backlog中缓存了大量无用的攻击请求如何查看当前队列的长度
通过ss命令即可看到当前队列的长度
99
总结
TCP backlog通过队列的方式来临时缓存请求,backlog的功能与火车站候车室的功能类似,当候车室人数过多时,我们不仅要增加候车室的容量,更重要的是要提升火车的拉客频率,来降低候车室的压力。