关于TCP队列问题和内核参数的优化

http请求或者https请求间歇性的被丢弃或者访问失败的排查流程
  1. 检查dev 和网卡设备层,是否有error和drop。硬件和系统层面错误。

    • cat /proc/net/dev
      • errors:由设备驱动程序检测到的发送或者接受错误的总数
      • drop:设备驱动程序丢弃包总数
    • ifconfig
  2. 观察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)中。
  3. 检查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)的值。
  4. 检查selinux和NetworkManager是否启用,禁用状态。
  5. 抓包判断请求进来后应用处理的情况,是否收到SYN未响应的情况。
验证
  1. 查看全连接队列(accept queue)溢出之后,OS处理设置:
    • cat /proc/sys/net/ipv4/tcp_abort_on_overflow
      • 0:表示如果三次握手第三步的时候全连接队列满了那么server扔掉client发过来的ack(在server端则会认为连接没有建立起来)
      • 1:表示如果三次握手第三步的时候全连接队列满了,server端就会发送一个reset包给client端,表示废弃这个握手过程和这个链接。(在server端也会认为连接没有建立起来)
  2. 设置tcp_abort_on_overflow为1
    • echo 1 > /proc/sys/net/ipv4/tcp_abort_on_overflow
  3. 查看server端的web服务是否存在许多的connection reset peer错误。
  4. 查看sysctl -a内核参数 backlog,somaxconn,file-max和nginx的blocklog参数。
  5. ss -lnt查看服务的Send-Q全队列的上限和Recv-Q的当前半链接的值。
  6. 内核参数优化:
    • net.ipv4.tcp_syncookies = 1
    • net.ipv4.tcp_max_syn_backlog = 16384
    • net.core.somaxconn = 16384
      • 最大极限值是65535。当超过了这个值的话需要转化为二进制,区最后16位,再转化为10进制。
  7. nginx参数优化
    • backlog = 32768
补充: SYN Flood洪水×××

当前最流行的DoS(拒绝服务×××)与DDos(分布式拒绝服务×××)的方式之一,这是一种利用TCP协议缺陷,导致被×××服务器保持大量的SYN_RECV状态的“半链接”,并且会重试默认的5次回应第二个握手包,塞满TCP等待连接队列,耗尽资源(CPU满负载或内存不足),让正常的业务请求连接不进来。