关于TCP队列问题和内核参数的优化
http请求或者https请求间歇性的被丢弃或者访问失败的排查流程
-
检查dev 和网卡设备层,是否有error和drop。硬件和系统层面错误。
- cat /proc/net/dev
- errors:由设备驱动程序检测到的发送或者接受错误的总数
- drop:设备驱动程序丢弃包总数
- ifconfig
- cat /proc/net/dev
-
观察socket overflow 和 socket droped。如果应用处理全连接队列(accept queue)过慢则会导致socket overflow,影响半连接队列(syn queue)溢出而导致socket dropped
- netstat -s | grep -i listen
- 645870725 times the listen queue of a socket overflowed
- 645990109 SYNs to LISTEN sockets ignored
- 隔段时间查看或者说监控SYN socket overflow和socket droped急剧增加的话则说明,TCP的三次握手是存在很大的问题的。
- 关于TCP三次握手的。
- client发送syn给server端。
- server接收到client的syn,这个时候则会将相关信息放到半链接队列(syn queue),并且发送syn+ack发送给client。
- client接受到server的syn+ack之后,发送一个ack给server告诉server我接收到了。这个时候server就会将相关信息放到全连接队列(accept queue)中。
- netstat -s | grep -i listen
-
检查sysctl内核参数。
- 内核参数详解sysctl -a
- fs.file-max:设置系统所有进程一共可以打开的文件数量。和ulimit的区别就是,ulimit设置的是当前shell以及由它启动的进程的资源限制。
- net.core.somaxconn:表示socket监听(listen)的backlog的上限,即全连接队列上限(accept queue)。backlog就是socket的监听队列,当一个请求(request)尚未被处理或建立时,它会进入backlog。而socket server可以一次性处理backlog中的所有请求,处理后的请求不在位于监听队列中。当server处理请求比较慢,以至于监听队列被填满后,新的请求会被拒绝。
- net.core.netdev_max_backlog:在每个网络接口接收数据包的速率比内核处理这些数据包快的时候,允许送到队列的数据包的最大数目。
- net.ipv4.tcp_max_syn_backlog:指定所能接受SYN同步包的最大客户端数量,即半连接队列(syn queue)上限
- net.ipv4.tcp_syncookies=1:表示开启SYN Cookies。当出现SYN等待队列溢出的时候,启用cookies来处理少量的SYN×××。
- net.ipv4.tcp_tw_reuse=1:表示开启tcp连接重用。表示允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭。
- net.ipv4.tcp_tw_recycle=1:表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。若是过NAT,则需要禁用这个参数。因为当同时在server端开启tcp_timestamps和recycle的时候,60s内同一源IP主机的socket connect请求中的timestamp必须是递增的。
- net.ipv4.tcp_timestamps:TCP时间戳(会在TCP包头增加12个字节)。
- ss -lnt查询。主要针对的是基于应用或者短裤的半链接当前值和全连接的上限值。
- Recv-Q:表示的是当前等待server端调用accept完成三次握手的listen backlog数值,也就是说,当客户端发送syn给server端,server端接收到syn存放的半连接队列(SYN queue)的当前值。
- Send-Q:表示全连接队列(accept queue)上限的数值,min(backlog,somaxconn)的值。
- 内核参数详解sysctl -a
- 检查selinux和NetworkManager是否启用,禁用状态。
- 抓包判断请求进来后应用处理的情况,是否收到SYN未响应的情况。
验证
- 查看全连接队列(accept queue)溢出之后,OS处理设置:
- cat /proc/sys/net/ipv4/tcp_abort_on_overflow
- 0:表示如果三次握手第三步的时候全连接队列满了那么server扔掉client发过来的ack(在server端则会认为连接没有建立起来)
- 1:表示如果三次握手第三步的时候全连接队列满了,server端就会发送一个reset包给client端,表示废弃这个握手过程和这个链接。(在server端也会认为连接没有建立起来)
- cat /proc/sys/net/ipv4/tcp_abort_on_overflow
- 设置tcp_abort_on_overflow为1
- echo 1 > /proc/sys/net/ipv4/tcp_abort_on_overflow
- 查看server端的web服务是否存在许多的connection reset peer错误。
- 查看sysctl -a内核参数 backlog,somaxconn,file-max和nginx的blocklog参数。
- ss -lnt查看服务的Send-Q全队列的上限和Recv-Q的当前半链接的值。
- 内核参数优化:
- net.ipv4.tcp_syncookies = 1
- net.ipv4.tcp_max_syn_backlog = 16384
- net.core.somaxconn = 16384
- 最大极限值是65535。当超过了这个值的话需要转化为二进制,区最后16位,再转化为10进制。
- nginx参数优化
- backlog = 32768
补充: SYN Flood洪水×××
当前最流行的DoS(拒绝服务×××)与DDos(分布式拒绝服务×××)的方式之一,这是一种利用TCP协议缺陷,导致被×××服务器保持大量的SYN_RECV状态的“半链接”,并且会重试默认的5次回应第二个握手包,塞满TCP等待连接队列,耗尽资源(CPU满负载或内存不足),让正常的业务请求连接不进来。