背景
最近遇到多台CVM中客户端访问服务器端超时的异常,当时查看了netstat -as信息,凭经验判断可能是tcp overflowed导致的。网卡队列满了,可能会造成子机网络包重传现象
探究全连接、半连接
但是全连接和半连接是什么回事呢?我们一起探究探究
这个得从TCP三次握手说起,
相信大家对三次握手都了然于胸,但是如果把这个过程放到linux环境下,结合linux内核的实现逻辑后是个什么形态呢?
这里有两个队列:
- 半连接队列:SYN queue ,长度由tcp_max_syn_backlog和net.core.somaxconn和 业务tcp调用listen(fd, backlog)的backlog三者最小值决定
- 全连接队列:ACCEPT queue , 长度由net.core.somaxconn和listen(fd, backlog)的backlog两者最小值决定
三次握手过程详情:
- Client端通过connect()系统调用,向Sever发起连接。发送SYN报文,进入SYN_SEND状态。
- Server收到SYN包,
- 如果全连接队列未满,将连接信息放到半连接队列中,进入SYN_RECV状态(也被称为半连接状态)。然后答复SYN ACK报文给Client
- 如果全连接队列满了,那么丢弃当前请求
- Client收到SYN ACK后,进行最后确认,向Server发送ACK报文,进入ESTABLISHED状态
- Server收到Client的ACK报文,
- 如果全连接队列未满,那么从半连接队列拿出相关信息放入到全连接队列中,进入ESTABLISHED状态
- 如果全连接队列满了并且tcp_abort_on_overflow是0的话,server过一段时间再次发送SYN ACK给Client(即重走握手的第二步)。如果Client超时等待设置较短,就会引发异常
监控方法
代码语言:javascript复制netstat -as
如下图中所示信息:
全连接队列满了:xxx times the listen queue of a socket overflowed
半连接队列满了:xxx SYNs to LISTEN sockets dropped
可以通过监控数值是否增加,来判断是否存在异常
优化方式
调高
net.core.somaxconn
net.ipv4.tcp_max_syn_backlog
同时,提升 listen(fd, backlog) 的 backlog