Linux CLOSE_WAIT TIME_WAIT 服务器 服务器优化 技术 Linux 下产生大量 TIME_WAIT 状态的原因和解决办法 2017-11-21 12:10 5763 更新于 2017-11-21 12:10 前几天搞聊天室的时候,看了下tcp状态,发现很多 TIME_WAIT 状态的tcp链接。了解了下,在这里做个记录。 ``` netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' ``` 可以看看有哪些 ``` netstat -anp | grep 9501 tcp 0 0 192.168.1.136:9501 192.168.1.100:63131 TIME_WAIT - tcp 0 0 192.168.1.136:9501 192.168.1.100:63105 TIME_WAIT - tcp 0 0 192.168.1.136:9501 192.168.1.100:63116 TIME_WAIT - tcp 0 0 192.168.1.136:9501 192.168.1.100:62561 TIME_WAIT - tcp 0 0 192.168.1.136:9501 192.168.1.100:63140 ESTABLISHED 21412/php tcp 0 0 192.168.1.136:9501 192.168.1.100:63121 TIME_WAIT - tcp 0 0 192.168.1.136:9501 192.168.1.100:63098 TIME_WAIT - .... ``` **大量的 TIME_WAIT 有什么危害** 若回收不及时,它会占用大量服务器资源,可能造成服务器无法提供服务的问题 产生 TIME_WAIT 的原因 先来看tcp状态图  A 为客户端, B 为服务器端 当页面使用ws链接到ws服务器时,就会产生一条状态为 ESTABLISHED 的tcp链接信息,当新开一个页面的时候,上一个页面的链接状态就会变为 TIME_WAIT(做了类似单点登录的功能)。两个页面互相刷新,将产生多个 TIME_WAIT 状态的 tcp 链接 ``` tcp 0 0 192.168.1.136:9501 0.0.0.0:* LISTEN 39045/php tcp 0 0 192.168.1.136:9501 192.168.1.100:62753 TIME_WAIT - tcp 0 0 192.168.1.136:9501 192.168.1.100:62724 TIME_WAIT - tcp 0 0 192.168.1.136:9501 192.168.1.100:62713 TIME_WAIT - tcp 0 0 192.168.1.136:9501 192.168.1.100:62778 ESTABLISHED 39045/php tcp 0 0 192.168.1.136:9501 192.168.1.100:56554 TIME_WAIT - tcp 0 0 192.168.1.136:9501 192.168.1.100:62693 TIME_WAIT - ... ``` 我的ws服务器做了心跳检查,时间一到会自动close,没问题。若其他情况呢?比如爬虫?syn攻击?这就要优化下服务器参数 在 `/etc/sysctl.conf` 中加入如下一些参数 ``` 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 = 5 #修改系统默认的 TIMEOUT 时间。 ``` 使用 /sbin/sysctl -p 使之生效 也可以使用 ``` cat /proc/sys/net/ipv4/tcp_fin_timeout ``` 来查看任意参数的默认值(将tcp_fin_timeout改为其他参数名即可) 这里再说一下 CLOSE_WAIT 这个状态,看上图可知,出现大量 CLOSE_WAIT 是因为服务器端没有发送 FIN 包给客户端(为什么不发送,原因多种多样),最主要的原因还是要优化代码,做到及时close 造成的结果也和 TIME_WAIT 差不多 当然也有几个参数可以优化下 ``` net.ipv4.tcp_keepalive_time=600 net.ipv4.tcp_keepalive_probes=2 net.ipv4.tcp_keepalive_intvl=30 ``` 意思: tcp链接在idle 600秒(默认两小时)后,服务器重试 2次,每次间隔30秒,若还是不能链接,认为该连接已失效 这样就能在短时间内回收没有关闭的 tcp 链接 ###关于 sysctl.conf 中的其他参数 #### $ /proc/sys/net/core/wmem_max 最大socket写buffer,可参考的优化值:873200 #### $ /proc/sys/net/core/rmem_max 最大socket读buffer,可参考的优化值:873200 #### $ /proc/sys/net/ipv4/tcp_wmemTCP 写buffer,可参考的优化值: 8192 436600 873200 #### $ /proc/sys/net/ipv4/tcp_rmemTCP 读buffer,可参考的优化值: 32768 436600 873200 #### $ /proc/sys/net/ipv4/tcp_mem 同样有3个值,意思是: net.ipv4.tcp_mem[0]:低于此值,TCP没有内存压力. net.ipv4.tcp_mem[1]:在此值下,进入内存压力阶段. net.ipv4.tcp_mem[2]:高于此值,TCP拒绝分配socket. 上述内存单位是页,而不是字节.可参考的优化值是:786432 1048576 1572864 #### $ /proc/sys/net/core/netdev_max_backlog 进入包的最大设备队列.默认是300,对重负载服务器而言,该值太低,可调整到1000. #### $ /proc/sys/net/core/somaxconn listen()的默认参数,挂起请求的最大数量.默认是128.对繁忙的服务器,增加该值有助于网络性能.可调整到256. #### $ /proc/sys/net/core/optmem_max socket buffer的最大初始化值,默认10K. #### $ /proc/sys/net/ipv4/tcp_max_syn_backlog 进入SYN包的最大请求队列.默认1024.对重负载服务器,增加该值显然有好处.可调整到2048. #### $ /proc/sys/net/ipv4/tcp_retries2 TCP失败重传次数,默认值15,意味着重传15次才彻底放弃.可减少到5,以尽早释放内核资源. #### $ /proc/sys/net/ipv4/tcp_keepalive_time #### $ /proc/sys/net/ipv4/tcp_keepalive_intvl #### $ /proc/sys/net/ipv4/tcp_keepalive_probes 这3个参数与TCP KeepAlive有关.默认值是: tcp_keepalive_time = 7200 seconds (2 hours) tcp_keepalive_probes = 9 tcp_keepalive_intvl = 75 seconds 意思是如果某个TCP连接在idle 2个小时后,内核才发起probe.如果probe 9次(每次75秒)不成功,内核才彻底放弃,认为该连接已失效.对服务器而言,显然上述值太大. 可调整到: /proc/sys/net/ipv4/tcp_keepalive_time 1800 /proc/sys/net/ipv4/tcp_keepalive_intvl 30 /proc/sys/net/ipv4/tcp_keepalive_probes 3 #### $ proc/sys/net/ipv4/ip_local_port_range 指定端口范围的一个配置,默认是32768 61000,已够大. **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。 [原文链接](https://blog.51cto.com/waringid/183496 "原文链接")