1、TCP常用内核参数优化
上一篇我们介绍了服务器上有大量的TIME_WAIT等待,可能造成的危害,以及给web服务器带来负担。如何解决这个问题呢,其实,解决思路很简单,就是让服务器能够快速回收和重用那些TIME_WAIT的资源即可。这就是对tcp调优。
在linux系统上,对tcp调优主要是通过调整Linux内核参数来实现的,其实主要是对/proc文件系统进行设置,/proc文件系统是一种内核和内核模块用来向进程(process) 发送信息的机制(所以叫做/proc)。通过这个伪文件系统我们可以和内核内部数据结构进行交互,在运行中改变内核参数。 与其他文件系统不同,/proc存在于内存之中而不是硬盘上。proc文件系统以文件的形式向用户空间提供了访问接口,这些接口可以用于在运行时获取相关信息或者修改参数配置,因而它是非常方便的一个接口。
/proc目录下存放着大多数的内核参数,并且可以在系统运行的同时进行更改, 但是,重新启动机器后就会失效,怎么解决呢,我们可以通过将更改的内核参数写入 /etc/sysctl.conf文件中实现永久更改,在/etc/sysctl.conf文件中添加或者修改如何设置:
#对于一个新建连接,内核要发送多少个SYN连接请求才决定放弃,不应该大于255,默认值是5,这里设置为2.
net.ipv4.tcp_syn_retries=2
#表示当keepalive启用的时候,TCP发送keepalive消息的频度。缺省是7200秒,改为300秒
net.ipv4.tcp_keepalive_time=300
#表示孤儿socket废弃前重试的次数,重负载web服务器建议调小。
net.ipv4.tcp_orphan_retries=1
#表示如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间
net.ipv4.tcp_fin_timeout=30
#表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。
net.ipv4.tcp_max_syn_backlog = 8192 (注意:这个队列大小除了系统设置外,程序里面也要设置)
#表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻 击,默认为0,表示关闭
net.ipv4.tcp_syncookies = 1
#表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭
net.ipv4.tcp_tw_reuse = 1
#表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭
net.ipv4.tcp_tw_recycle = 1
修改完之后执行/sbin/sysctl -p让参数生效。
其实TIME-WAIT的问题还是比较好处理的,可以通过调节服务器参数实现,有时候还会出现CLOSE_WAIT很多的情况,CLOSE_WAIT是在对方关闭连接之后服务器程序自己没有进一步发出ACK信号。换句话说,就是在对方连接关闭之后,程序里没有检测到,或者程序压根就忘记了这个时候需要关闭连接,于是这个资源就一直被程序占着。所以解决CLOSE_WAIT过多的方法还需要检查程序,检查代码,因为问题很大程度上出在服务器程序中。
到此为止,TCP优化到一段落。

2、TCP洪水攻 击(SYN Flood)的诊断和处理
SYN Flood是当前最流行的DoS(拒绝服务)与DDoS(分布式拒绝服务)的方式之一,这是一种利用TCP协议缺陷,发送大量伪造的TCP连接请求,常用假冒的IP或IP号段发来海量的请求连接第一个握手包(SYN包),被攻 击服务器回应第二个握手包(SYN+ACK包),因为对方是假冒IP,对方永远收不到包且不会回应第三个握手包。导致被攻 击服务器保持大量SYN_RECV状态的“半连接”,并且会重试默认5次回应第二个握手包,直到塞满TCP等待连接队列,资源耗尽(CPU满负荷或内存不足),让正常的业务请求连接不进来。
那么如何诊断SYN Flood问题呢,一般情况下如果发现网站打开缓慢、CPU负载高、ssh登陆慢甚至登陆不上,同时在系统日志中发现如下信息:
[root@test ~]# tail -f /var/log/messages
Mar 12 02:38:03 test kernel: possible SYN flooding on port 80. Sending cookies.
Mar 12 02:39:04 test kernel: possible SYN flooding on port 80. Sending cookies.
Mar 12 02:40:04 test kernel: possible SYN flooding on port 80. Sending cookies.
如果出现类似这种情况,那可能就是遭遇了TCP洪水***。

此时,通过如下命令检查TCP连接状态:
[root@localhost ~]# netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
TIMEWAIT 7807
FINWAIT1 59
ESTABLISHED 8112
FINWAIT2 809
SYNRECV 198098
CLOSING 27
LASTACK 36
检查发现,SYNRECV连接数会非常多。
针对这个问题,首先要做应急处理,那就是找到请求数请最多的IP地址,查找攻 击来源,使用如下命令组合:
[root@localhost ~]# netstat -anlp|grep 80|grep tcp|awk '{print $5}'|awk -F: '{print $1}'|sort|uniq -c|sort -nr|head -n3
36.171.242
149.130.152
149.130.18
查到可疑的IP后,利用iptables临时封掉最大嫌疑攻 击的IP或IP号段。
接着,还需要调整系统内核参数,来抵挡这种攻 击,根据上面对SYN Flood攻 击的特点,我们只需修改操作系统内核参数即可有效缓解。主要参数如下:
net.ipv4.tcpsyncookies = 1
net.ipv4.tcpmaxsynbacklog = 81920
net.ipv4.tcpsynackretries = 2
三个参数的含义分别为启用SYN Cookie、设置SYN最大队列长度以及设置SYN+ACK最大重试次数。
SYN Cookie的作用是缓解服务器资源压力。启用之前,服务器在接到SYN数据包后,会立即分配存储空间,并随机化一个数字作为SYN号发送SYN+ACK数据包。然后保存连接的状态信息等待客户端确认。而在启用SYN Cookie之后,服务器不再马上分配存储空间,而且通过基于时间种子的随机数算法设置一个SYN号,替代完全随机的SYN号。发送完SYN+ACK确认报文之后,清空资源不保存任何状态信息。直到服务器接到客户端的最终ACK包。同时,通过Cookie检验算法鉴定是否与发出去的SYN+ACK报文序列号匹配,匹配则通过完成握手,失败则丢弃。
tcpmaxsynbacklog则是使用服务器的内存资源,换取更大的等待队列长度,让攻 击数据包不至于占满所有连接而导致正常用户无法完成握手。
net.ipv4.tcpsynackretries是降低服务器SYN+ACK报文重试次数(默认是5次),尽快释放等待资源。
这三种措施与攻 击的三种危害一一对应,完完全全是对症下药。但这些措施也是双刃剑,设置过大可能消耗服务器更多的内存资源,甚至影响正常用户建立TCP连接,因此,需要评估服务器硬件资源和大小谨慎设置。