netstat 查看系统连接情况,出现 FIN_WAIT1:

防止linux出现大量 FIN_WAIT1-LMLPHP

当连接数多时,经常出现大量FIN_WAIT1,可以修改 /etc/sysctl.conf以下参数:

net.ipv4.tcp_fin_timeout = 10

net.ipv4.tcp_keepalive_time = 30

net.ipv4.tcp_window_scaling = 0

net.ipv4.tcp_sack = 0

然后执行/sbin/sysctl -p使其生效。

场景分析

1)time_wait状态过多

通常表现为apache服务器负载高,w命令显示load average可能上百,但是web服务基本没有问题。同时ssh能够登陆,但是反应非常迟钝。

原因:最可能的原因是httpd.conf里面keepalive没有开,导致每次请求都要建立新的tcp连接,请求完成以后关闭,增加了很多 time_wait的状态。另,keepalive可能会增加一部分内存的开销,但是问题不大。

2)fin_wait1状态过多。

fin_wait1状态是在server端主动要求关闭tcp连接,并且主动发送fin以后,等待client端回复ack时候的状态。fin_wait1的产生原因有很多,需要结合netstat的状态来分析。

netstat -nat|awk '{print awk $NF}'|sort|uniq -c|sort -n

上面的命令可以帮助分析哪种tcp状态数量异常

netstat -nat|grep ":80"|awk '{print $5}' |awk -F: '{print $1}' | sort| uniq -c|sort -n

则可以帮助你将请求80服务的client ip按照连接数排序。

回到fin_wait1这个话题,如果发现fin_wait1状态很多,并且client ip分布正常,那可能是有人用肉鸡进行ddos攻击、又或者最近的程序改动引起了问题。一般说来后者可能性更大,应该主动联系程序员解决。

但是如果有某个ip连接数非常多,就值得注意了,可以考虑用iptables直接封了他。

Linux下查看Apache的请求数

在Linux下查看Apache的负载情况,以前也说过,最简单有有效的方式就是查看Apache Server Status(如何开启Apache Server Status点这里),在没有开启Apache Server Status的情况下,或安装的是其他的Web Server,比如Nginx的时候,下面的命令就体现出作用了。

ps -ef|grep httpd|wc -l命令

#ps -ef|grep httpd|wc -l

1388

统计httpd进程数,连个请求会启动一个进程,使用于Apache服务器。

表示Apache能够处理1388个并发请求,这个值Apache可根据负载情况自动调整,我这组服务器中每台的峰值曾达到过2002。

netstat -nat|grep -i "80"|wc -l命令

#netstat -nat|grep -i "80"|wc -l

4341

netstat -an会打印系统当前网络链接状态,而grep -i “80″是用来提取与80端口有关的连接的, wc -l进行连接数统计。

最终返回的数字就是当前所有80端口的请求总数。

netstat -na|grep ESTABLISHED|wc -l命令

#netstat -na|grep ESTABLISHED|wc -l

376

netstat -an会打印系统当前网络链接状态,而grep ESTABLISHED 提取出已建立连接的信息。然后wc -l统计。

最终返回的数字就是当前所有80端口的已建立连接的总数

netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'命令

#netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

FIN_WAIT_1 286

FIN_WAIT_2 960

SYN_SENT 3

LAST_ACK 32

CLOSING 1

CLOSED 36

SYN_RCVD 144

TIME_WAIT 2520

ESTABLISHED 352

这条语句是在张宴那边看到,据说是从新浪互动社区事业部技术总监王老大那儿获得的,非常不错。返回参数的说明如下:

  • SYN_RECV表示正在等待处理的请求数;
  • ESTABLISHED表示正常数据传输状态;
  • TIME_WAIT 表示处理完毕,等待超时结束的请求数。

调优, 性能, 优化

1)解决linux下大量的time_wait问题

vi /etc/sysctl.conf

编辑/etc/sysctl.conf文件,增加三行:

引用

net.ipv4.tcp_fin_timeout = 30

net.ipv4.tcp_keepalive_time = 1200

net.ipv4.tcp_syncookies = 1

net.ipv4.tcp_tw_reuse = 1

net.ipv4.tcp_tw_recycle = 1

net.ipv4.ip_local_port_range = 1024 65000

net.ipv4.tcp_max_syn_backlog = 8192

net.ipv4.tcp_max_tw_buckets = 5000

net.ipv4.route.gc_timeout = 100

net.ipv4.tcp_syn_retries = 1

net.ipv4.tcp_synack_retries = 1

说明:

  • net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;
  • net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
  • net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。

再执行以下命令,让修改结果立即生效:

/sbin/sysctl -p

用以下语句看了一下服务器的TCP状态:

netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

返回结果如下:

ESTABLISHED 1423

FIN_WAIT1 1

FIN_WAIT2 262

SYN_SENT 1

TIME_WAIT 962

效果:处于TIME_WAIT状态的sockets从原来的10000多减少到1000左右。处于SYN_RECV等待处理状态的sockets为0,原来的为50~300。

通过上面的设置以后,你可能会发现一个新的问题,就是netstat时可能会出现这样的警告:

warning, got duplicate tcp line

这正是上面允许tcp复用产生的警告,不过这不算是什么问题,总比不允许复用而给服务器带来很大的负载合算的多

解决办法:

1)安装rpm包:

[root@root2 opt]# rpm -Uvh net-tools-1.60-62.1.x86_64.rpm

Preparing... ########################################### [100%]

1:net-tools ########################################### [100%]

对于下载的是源码的rpm则需要使用以下方法安装:

2)安装rpm源码包方法:

a) 安装src.rpm:

# [root@root1 opt]# rpm -i net-tools-1.60-62.1.src.rpm

……

b) 制作rpm安装包:

[root@root1 opt]# cd /usr/src/redhat/SPECS/

[root@root1 SPECS]# rpmbuild -bb net-tools.spec

c) rpm包的升级安装:

[root@root1 SPECS]# pwd

/usr/src/redhat/SPECS

[root@root1 SPECS]# cd ../RPMS/x86_64/

[root@root1 x86_64]# rpm -Uvh net-tools-1.60-62.1.x86_64.rpm

3、 再使用netstat来检查时系统正常:

说明:

  • net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;
  • net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
  • net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
  • net.ipv4.tcp_fin_timeout = 30 表示如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间。  
  • net.ipv4.tcp_keepalive_time = 1200 表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时,改为20分钟。  
  • net.ipv4.ip_local_port_range = 1024 65000 表示用于向外连接的端口范围。缺省情况下很小:32768到61000,改为1024到65000。  
  • net.ipv4.tcp_max_syn_backlog = 8192 表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。
  • net.ipv4.tcp_max_tw_buckets = 5000 表示系统同时保持TIME_WAIT套接字的最大数量,如果超过这个数字,TIME_WAIT套接字将立刻被清除并打印警告信息。默认为180000,改为5000。对于Apache、Nginx等服务器,上几行的参数可以很好地减少TIME_WAIT套接字数量,但是对于Squid,效果却不大。此项参数可以控制TIME_WAIT套接字的最大数量,避免Squid服务器被大量的TIME_WAIT套接字拖死。
  • net.ipv4.route.gc_timeout = 100 路由缓存刷新频率, 当一个路由失败后多长时间跳到另一个,默认是300
  • net.ipv4.tcp_syn_retries = 1 对于一个新建连接,内核要发送多少个 SYN 连接请求才决定放弃。不应该大于255,默认值是5,对应于180秒左右。
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

先设置fin-wait-1状态,然后再发fin包。理论上说,fin-wait-1的状态应该很难看到才对,因为只要收到对方的ack,就应该迁移到fin-wait-2了,如果收到对方的fin,则应该迁移到closing状态

为什么会有FIN_WAIT1?

FIN_WAIT1是由于服务端主动关闭连接,服务器端发出请求后,等待客户端的响应。如果这时候连接已经断掉了,那么Linux内核会主动Retry再次多次发送主动关闭连接的请求。以Swoole来说,就是代码执行了Swoole的$serv->close($fd)方法。

这个请求的次数,Linux内核里默认是0。通过查看Linux的代码,会发现这个0并不是一次都不尝试的意思。而是,尝试次数为8。也就是说,服务端主动关闭连接如果客户端不响应,那么每个连接Linux都会默认尝试8次。对于维护大量连接的服务端来说,这就比较蛋疼了。要把这个值改小一点

修改FIN_WAIT连接的重试次数

vim /etc/sysctl.conf 打开内核配置文件。linux内核是不能直接修改的,把新的配置写入这个文件,会覆盖Linux内核的文件。

net.ipv4.tcp_orphan_retries = 1

把这行代码插入/etc/sysctl.conf 文件,就是把retry次数设为1。我个人是建议设置为2的,经过实测,设置为2,FIN_WAIT1的连接数量就从四位数降低到个位数了。

防止linux出现大量 FIN_WAIT1-LMLPHP

 防止linux出现大量 FIN_WAIT1-LMLPHP

04-04 00:37