先上两张图:

查看TIME_WAIT和CLOSE_WAIT数的命令:

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

它会显示例如下面的信息:

TIME_WAIT 、CLOSE_WAIT 、FIN_WAIT1 、ESTABLISHED 、SYN_RECV 、LAST_ACK  常用的三个状态是:ESTABLISHED表示正在通信 、TIME_WAIT表示主动关闭、CLOSE_WAIT表示被动关闭。

服务器出现异常最长出现的状况是:

  1. 服务器保持了大量的TIME_WAIT状态。
  2. 服务器保持了大量的CLOSE_WAIT状态。

我们也都知道Linux系统中分给每个用户的文件句柄数是有限的,而TIME_WAIT和CLOSE_WAIT这两种状态如果一直被保持,那么意味着对应数目的通道(此处应理解为socket,一般一个socket会占用服务器端一个端口,服务器端的端口最大数是65535)一直被占用,一旦达到了上限,则新的请求就无法被处理,接着就是大量Too Many Open Files异常,然后tomcat、nginx、apache崩溃。。。

下面来讨论这两种状态的处理方法,网络上也有很多资料把这两种情况混为一谈,认为优化内核参数就可以解决,其实这是不恰当的。优化内核参数在一定程度上能解决time_wait过多的问题,但是应对close_wait还得从应用程序本身出发。

服务器保持了大量的time_wait状态

  这种情况比较常见,一般会出现在爬虫服务器和web服务器(如果没做内核参数优化的话)上,那么这种问题是怎么产生的呢?

从上图可以看出time_wait是主动关闭连接的一方保持的状态,对于爬虫服务器来说它自身就是客户端,在完成一个爬取任务后就会发起主动关闭连接,从而进入time_wait状态,然后保持这个状态2MSL时间之后,彻底关闭回收资源。这里为什么会保持资源2MSL时间呢?这也是TCP/IP设计者规定的。

TCP要保证在所有可能的情况下使得所有的数据都能够被正确送达。当你关闭一个socket时,主动关闭一端的socket将进入TIME_WAIT状 态,而被动关闭一方则转入CLOSED状态,这的确能够保证所有的数据都被传输。当一个socket关闭的时候,是通过两端四次握手完成的,当一端调用 close()时,就说明本端没有数据要发送了。这好似看来在握手完成以后,socket就都可以处于初始的CLOSED状态了,其实不然。原因是这样安排状态有两个问题, 首先,我们没有任何机制保证最后的一个ACK能够正常传输,第二,网络上仍然有可能有残余的数据包(wandering duplicates),我们也必须能够正常处理。

TIMEWAIT就是为了解决这两个问题而生的。

  1. 假设最后的一个ACK丢失,那么被动关闭一方收不到这最后一个ACK则会重发FIN。此时主动关闭一方必须保持一个有效的(time_wait状态下维持)状态信息,以便可以重发ACK。如果主动关闭的socket不维持这种状态而是进入close状态,那么主动关闭的一方在收到被动关闭方重新发送的FIN时则响应给被动方一个RST。被动方收到这个RST后会认为此次回话出错了。所以如果TCP想要完成必要的操作而终止双方的数据流传输,就必须完全正确的传输四次握手的四步,不能有任何的丢失。这就是为什么在socket在关闭后,任然处于time_wait状态的第一个原因。因为他要等待可能出现的错误(被动关闭端没有接收到最后一个ACK),以便重发ACK。
  2. 假设目前连接的通信双方都调用了close(),双方同时进入closed的终结状态,而没有走 time_wait状态。则会出现如下问题:假如现在有一个新的连接建立起来,使用的IP地址与之前的端口完全相同,现在建立的一个连接是之前连接的完全复用,我们还假定之前连接中有数据报残存在网络之中,这样的话现在的连接收到的数据有可能是之前连接的报文。为了防止这一点。TCP不允许新的连接复用time_wait状态下的socket。处于time_wait状态的socket在等待2MSL时间后(之所以是两倍的MSL,是由于MSL是一个数据报在网络中单向发出 到认定丢失的时间,即(Maximum Segment Lifetime)报文最长存活时间,一个数据报有可能在发送途中或是其响应过程中成为残余数据报,确认一个数据报及其响应的丢弃需要两倍的MSL),将会转为closed状态。这就意味着,一个成功建立的连接,必须使得之前网络中残余的数据报都丢失了。

再引用网络中的一段话:

  1. 值得一说的是,基于TCP的http协议,一般(此处为什么说一般呢,因为当你在keepalive时间内 主动关闭对服务器端的连接时,那么主动关闭端就是客户端,否则客户端就是被动关闭端。下面的爬虫例子就是这种情况)主动关闭tcp一端的是server端,这样server端就会进入time_wait状态,可想而知,对于访问量大的web服务器,会存在大量的time_wait状态,假如server一秒钟接收1000个请求,那么就会积压240*1000=240000个time_wait状态。(RFC 793中规定MSL为2分钟,实际应用中常用的是30秒,1分钟和2分钟等。),维持这些状态给服务器端带来巨大的负担。当然现代操作系统都会用快速的查找算法来管理这些 TIME_WAIT,所以对于新的 TCP连接请求,判断是否hit中一个TIME_WAIT不会太费时间,但是有这么多状态要维护总是不好。
  2. HTTP协议1.1版本规定default行为是keep-Alive,也就是会重用tcp连接传输多个 request/response。之所以这么做的主要原因是发现了我们上面说的这个问题。

服务器保持了大量的close_wait状态:

  time_wait问题可以通过调整内核参数和适当的设置web服务器的keep-Alive值来解决。因为time_wait是自己可控的,要么就是对方连接的异常,要么就是自己没有快速的回收资源,总之不是由于自己程序错误引起的。但是close_wait就不一样了,从上图中我们可以看到服务器保持大量的close_wait只有一种情况,那就是对方发送一个FIN后,程序自己这边没有进一步发送ACK以确认。换句话说就是在对方关闭连接后,程序里没有检测到,或者程序里本身就已经忘了这个时候需要关闭连接,于是这个资源就一直被程序占用着。这个时候快速的解决方法是:

  1. 关闭正在运行的程序,这个需要视业务情况而定。
  2. 尽快的修改程序里的bug,然后测试提交到线上服务器。

注:

直到写这篇文章的时候我才完全弄明白之前工作中遇到的一个问题。程序员写了爬虫(php)运行在采集服务器A上,程序去B服务器上采集资源,但是A服务器很快就发现出现了大量的close_wait状态的连接。后来手动检查才发现这些处于close_wait状态的请求结果都是404,那就说明B服务器上没有要请求的资源。

下面引用网友分析的结论:

服 务器A是一台爬虫服务器,它使用简单的HttpClient去请求资源服务器B上面的apache获取文件资源,正常情况下,如果请求成功,那么在抓取完 资源后,服务器A会主动发出关闭连接的请求,这个时候就是主动关闭连接,服务器A的连接状态我们可以看到是TIME_WAIT。如果一旦发生异常呢?假设 请求的资源服务器B上并不存在,那么这个时候就会由服务器B发出关闭连接的请求,服务器A就是被动的关闭了连接,如果服务器A被动关闭连接之后程序员忘了 让HttpClient释放连接,那就会造成CLOSE_WAIT的状态了。

服务器TIME_WAIT和CLOSE_WAIT分析和解决办法的更多相关文章

  1. 一次TIME_WAIT和CLOSE_WAIT故障和解决办法

    昨天解决了一个curl调用错误导致的服务器异常,具体过程如下: 里头的分析过程有提到,通过查看服务器网络状态检测到服务器有大量的CLOSE_WAIT的状态. 在服务器的日常维护过程中,会经常用到下面的 ...

  2. 服务器TIME_WAIT和CLOSE_WAIT详解和解决办法

    转载的服务器TIME_WAIT和CLOSE_WAIT详解和解决办法

  3. JavaScript中的ParseInt("08")和“09”返回0的原因分析及解决办法

    今天在程序中出现一个bugger ,调试了好久,最后才发现,原来是这个问题. 做了一个实验: alert(parseInt("01")),当这个里面的值为01====>07时 ...

  4. php中session_start()相关问题分析与解决办法

    介绍下,在php中使用session时遇到的一些问题,与相关解决方法.1.错误提示Warning: Cannot send session cookie - headers already sentW ...

  5. oracle执行update语句时卡住问题分析及解决办法

    转载:http://www.jb51.net/article/125754.htm 这篇文章主要介绍了oracle执行update语句时卡住问题分析及解决办法,涉及记录锁等相关知识,具有一定参考价值, ...

  6. HTML5服务器推送消息的各种解决办法,html5服务器

    HTML5服务器推送消息的各种解决办法,html5服务器 摘要 在各种BS架构的应用程序中,往往都希望服务端能够主动地向客户端推送各种消息,以达到类似于邮件.消息.待办事项等通知. 往BS架构本身存在 ...

  7. selenium元素定位不到问题分析及解决办法

    最近正在学习写自动化测试脚本,遇到一个错误迟迟未解决,导致自信心大受挫败,甚至想放弃. 思考许久突然想到,我遇到的问题是否也有人会遇到,如果有的话问题就应该有解决办法了.没什么问题是百度解决不了的,如 ...

  8. 服务器CPU使用率高的原因分析与解决办法

    我们的服务器在使用操作系统的时候,用着用着系统就变慢了,打开“ 任务管理器 ”一看,才发现CPU使用率达到80%以上.这是怎么回事情呢?遇到病毒了吗?硬件有问题?还是系统设置有问题呢?在本文中将从硬件 ...

  9. Nested Loops join时显示no join predicate原因分析以及解决办法

    本文出处:http://www.cnblogs.com/wy123/p/6238844.html 最近遇到一个存储过程在某些特殊的情况下,效率极其低效, 至于底下到什么程度我现在都没有一个确切的数据, ...

随机推荐

  1. JS高级学习历程-17

    [正则案例] 1 匹配手机号码

  2. safari不支持new Date函数

    最近在做移动Web的时候,在PC上用Chrome调试都成功了,但是在iPhone上真机一测就出现了奇怪的问题.经过一系列调试发现是日期相关的地方出现了问题.起初怀疑是生产环境的问题,但用Mac版的sa ...

  3. Yii2.0权限系统,使用PhpManager的方式

    网上搜了一大堆yii2.0权限系统,大抵都是千篇一律,而且基本上都是DbManager.看了半天官方文档之后,终于知道了PhpManager的方式下,是怎么引入权限系统.介绍下我自己的使用.首先,配置 ...

  4. High waits on control file sequential read

    High waits on control file sequential read (文档 ID 2277867.1) In case we run into an issue where cont ...

  5. POJ 3735 Training little cats 矩阵快速幂

    http://poj.org/problem?id=3735 给定一串操作,要这个操作连续执行m次后,最后剩下的值. 记矩阵T为一次操作后的值,那么T^m就是执行m次的值了.(其实这个还不太理解,但是 ...

  6. 跟老男孩学Linx运维---web集群实战笔记

    2018/01/05 2018/01/04 安装:PHP扩展插件PDO_MYSQL-1.0.2报错 In file included from /home/wasadmin/PDO_MYSQL-1.0 ...

  7. SSIS连接-左外连接

    应用场景: 当有多个数据源时,可能是在不同的数据库,或者是一个数据源来自数据库,另一个来自excel文件,想要把他们合并,像sql的左外联接时,应用到 源1: select 'A01' GoodsNo ...

  8. vuejs 组件 移动端push 没有渲染页面

    this.idcards.push(arr) 这个无效 就知道了 vuejs有个跟push相同的方法 console.log(this.list.push.toString()) 这个push是个同名 ...

  9. MySql自动默认时间及更新时间

    注意:5.7 才能用类型为datetime的字段实现 `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `modifie ...

  10. 【TensorFlow入门完全指南】神经网络篇·循环神经网络(RNN)

    第一步仍然是导入库和数据集. ''' To classify images using a reccurent neural network, we consider every image row ...