1、阐述

  内部架构:Tomcat应用程序---> nginx ---> 其他Tomcat应用程序,内部Tomcat应用通过nginx调用其他应用。

  HTTP插件:HttpClient 4.2.3

  关闭连接的代码:httpClient.getConnectionManager().closeIdleConnections(5, TimeUnit.SECONDS);

2、说明

  要说明的是CLOSE_WAIT产生的原因和服务器、nginx、其他配置无关,是HttpClient的getConnectionManager引起的。

3、排查思路

  这个问题已经困扰我很久了,查看过网上的很多办法,也试过很多方法。

  比如:修改服务器内核、修改nginx配置文件、更改nginx版本,都是没有用的,还是上面那句话和服务器、nginx无关。

  最后决定自己分析请求,查找真正的根本原因,以下为排查的最终步骤

4、问题排查

  首先确认CLOSE_WAIT产生的链接,链接的IP和端口

  

  由上图看出是本机链接nginx 81端口造成的CLOSE_WAIT

  抓包分析其中一个CLOSE_WAIT所用的本机端口:

  抓包分析正常关闭的请求:

  分析不正常端口41584,晚上22点01分02秒请求连接,22点01分02秒传输数据结束,22点02分07秒,nginx发送关闭连接的包,Tomcat同意关闭,问题就出现在这里,在Nginx请求关闭连接后,Tomcat并没有回复同样关闭连接的包,没有完成四次握手,故产生了CLOSE_WAIT。

  分析所有正常连接发现没有产生CLOSE_WAIT的端口都是Tomcat主动关闭的,产生CLOSE_WAIT的都是nginx主动关闭,Tomcat被动关闭的。

  再次分析所有的不正常端口

  发现Tomcat周期性的向Nginx发送关闭连接的请求,但是Nginx回复Reset包,说白了就是Tomcat请求关闭连接,但是Nginx说我没有这个链接(已经在前面主动关闭),所有CLOSE_WAIT会一直存在,直至两个小时以后系统强制关闭。至于为什么会周期性的一起并发的关闭的连接,而不是一个一个关闭,或者为什么在收到Nginx关闭连接请求,Tomcat不关闭,看上述Java代码:httpClient.getConnectionManager().closeIdleConnections(5, TimeUnit.SECONDS);

  这段代码表示调用httpClient的getConnectionManager,然后利用closeIdleConnections进行关闭空闲连接,5代表是五秒(不知道解释的对不对)。

  网上查找getConnectionManager,说是httpclient的链接池管理工具。就是把请求都扔里面,然后Manager帮你做相关处理。

  但是上述代码写的是5秒之内连接空闲就会连接,httpclient又是一个很成熟的技术,于是没有怀疑这个的问题(我不是开发,代码层我无法分析)。

  继续分析其他正常关闭的包,发现并不是所有正常关闭的连接都是五秒关闭的,而产生CLOSE_WAIT的,一般请求关闭都是超过65秒的(65是nginx keepalive timeout的值),为了确认问题的根源,我把nginx的keepalive timeout设置为240秒(Nginx主动关闭连接后,最长Tomcat第一次发送关闭连接的包据数据传输完毕的时间间隔为3分28秒),实时查看CLOSE的增长变得缓慢,改为360秒,几乎不怎么增长,但是还有增长,索性改为0,过了一个多小时,只会下降,不会增多,所以断定是HTTPCLIENT出现的问题。

5、继续分析

  查看httpclient官方文档:http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/conn/ClientConnectionManager.html

  上面说在给定的时间内(上述代码的五秒)链接没有被使用,就会在池中关闭连接。同时也会关闭过期的连接。

  看解释说只要连接5秒没有被使用,就会关闭连接,不会大于65秒的,至此又回到诧异懵逼中。。。

  再次回想连接池中周期性发送FIN包,让我判断没有在五秒内关闭连接只有两种可能:一、配置没有生效,二、HTTPCLIENT空闲连接检测机制。

  把自己的想法说给开发人员说后,决定修改代码,换用另一种关闭的方式(没有时间考虑上面的两个想法):将所有完成请求通过httpclient的releaseConnection和SHUTDOWN进行关闭,修改完成并在测试环境部署(测试环境也同样有CLOSE_WAIT),运行至今并无产生任何CLOSE_WAIT。

6、总结

  CLOSE_WAIT产生的原因是由代码引起的,目前能确认的是HTTPCLIENT的getConnectionManager的连接池引起的,但是为什么设置的5秒没有生效,空闲连接的检测机制是什么,这些还无法得知。

  

  

  

  

我是如何确认线上CLOSE_WAIT产生的原因及如何解决的。的更多相关文章

  1. 一次线上http接口调用不通相关的解决过程

    2016-05-25 08:58:34 昨天线上小白系统因为调用外部http接口,超时不释放,导致页面反应很慢,时间一长,报502错误. 上网查了下,502错误是因为服务对于客户的请求没有得到及时的反 ...

  2. 线上Redis偶发性链接失败排查记

    问题过程 输入法业务于12月12日上线了词库接受业务,对部分用户根据用户uuid判断进行回传,在12月17日早上8点多开始出现大量的php报错(Redis went away),报错导致了大量的链接积 ...

  3. 线上bug分析

    昨天下午大神把组内几十号人召集在一起开Online bug分析大会,主要是针对近期线上事故从事故原因和解决方案两个维度来分析. 对金融软件来说,每一次的线上事故都有可能给公司带来重大的损失,少扣了用户 ...

  4. 线上一次大量 CLOSE_WAIT 复盘

    https://mp.weixin.qq.com/s/PfM3hEsDa3CMLbbKqis-og 线上一次大量 CLOSE_WAIT 复盘 原创 ms2008 poslua 2019-07-05 最 ...

  5. [Nginx笔记]关于线上环境CLOSE_WAIT和TIME_WAIT过高

    运维的同学和Team里面的一个同学分别遇到过Nginx在线上环境使用中会遇到TIME_WAIT过高或者CLOSE_WAIT过高的状态 先从原因分析一下为什么,问题就迎刃而解了. 首先是TIME_WAI ...

  6. 分布式存储 FastDFS-5.0.5线上搭建

    前言:       由于公司项目需要,最近开始学习一下分布式存储相关知识,确定使用FastDFS这个开源工具.学习之初,自己利用VMware虚拟机搭建了一个5台机器的集群,摸清了安装过程中可能出现的问 ...

  7. 线上Linux服务器运维安全策略经验分享

    线上Linux服务器运维安全策略经验分享 https://mp.weixin.qq.com/s?__biz=MjM5NTU2MTQwNA==&mid=402022683&idx=1&a ...

  8. 【阿里云产品公测】OTS使用之简单线上产品实践基于PythonSDK

    阿里云用户:morenocjm 实践是检验真理的唯一标准,学习技术需要通过实践过程中的不断尝试,才能够快速掌握要领.OTS是构建在阿里云飞天分布式系统之上的NoSQL数据库服务,提供海量结构化数据的存 ...

  9. 【微学堂】线上Linux服务器运维安全策略经验分享

      技术转载:https://mp.weixin.qq.com/s?__biz=MjM5NTU2MTQwNA==&mid=402022683&idx=1&sn=6d403ab4 ...

随机推荐

  1. 并行设计模式(二)-- Master-Worker模式

    Java多线程编程中,常用的多线程设计模式包括:Future模式.Master-Worker模式.Guarded Suspeionsion模式.不变模式和生产者-消费者模式等.这篇文章主要讲述Mast ...

  2. SaltStack 架构自动部署 03

    架构图 模块化部署 系统模块:系统优化,内核参数,网络参数 功能模块:如:nginx,tomcat, 业务模块: 1.在salt-master端修改配置文件 [root@01 salt]# vim / ...

  3. 一道JS 连续赋值运算的问题

    原文链接:https://www.cnblogs.com/joesbell/p/6229423.html <script> var a = {n:1}; var b = a; a.x = ...

  4. php获取当前月与上个月月初及月末时间戳的方法

    php 获取今日.昨日.上周.本月的起始时间戳和结束时间戳的方法,主要使用到了 php 的时间函数 mktime.下面首先还是直奔主题以示例说明如何使用 mktime 获取今日.昨日.上周.本月的起始 ...

  5. jquery类数组结构学习笔记

    大家都知道我们使用$()产生的jquery对象可以使用下标去获取对应下标的元素. 举个栗子,一个页面有5个div标签,我们使用$("div")去获取到这些元素,然后我们就可以使用$ ...

  6. Python 简单的输出

    Python hw其实非常简单. 2 行代码 vi test.py [Python] 纯文本查看 复制代码 ? 1 2 #!/usr/bin/python print "Hello Worl ...

  7. JavaScript学习总结(一)——ECMAScript、BOM、DOM(核心、浏览器对象模型与文档对象模型)

    一.JavaScript简介 JavaScript是一种解释执行的脚本语言,是一种动态类型.弱类型.基于原型的语言,内置支持类型,它遵循ECMAScript标准.它的解释器被称为JavaScript引 ...

  8. springMVC使用jsp:include嵌入页面的两种方式

    1.静态嵌入子页面 <%@ include file="header.jsp" %>   静态嵌入支持 jsp . html . xml 以及纯文本. 静态嵌入在编译时 ...

  9. Qt 显示图片的三种方法

    一. 直接用QLabel显示原图 //单独显示的QLabel 其大小为内容即图片的大小,若将QLabel放入QMainWindow中则QLabel的大小为其初始大小. /* QLabel *label ...

  10. java学习笔记之日期日历类

    java学习笔记之日期日历 Date日期类概述: 表示特定的瞬间,精确到毫秒 Date类的构造方法: 1.空参数构造方法 Date date = new Date(); 获取到当前操作系统中的时间和日 ...