服务器出现大量close_wait,我们来说说到底是怎么回事?(以tomcat为例)
一、问题描述
最近一直忙得很,好久没写博客。前两天,微信收到个好友申请,说是想问问close_wait的事情。
找他问了些详细信息,大概了解到,他们后端服务是tomcat 7, jdk 7,centos,传统的spring + hibernate + spring mvc 结构。
业务不清楚,客户端主要是微信小程序。
目前的症状就是,服务器上有大量的close_wait状态的连接,在他们的服务器上执行 netstat 命令,如下图:
从上图看出,他们的服务器ip为 172.18.206.252(反正是内网ip,不用打码了吧),端口是443,那应该就是https服务了。
客户端ip没有重样的,应该都是些全国各地的ip了。
close_wait的危害在于,在一个端口上打开的文件描述符超过一定数量,(在linux上默认是1024,可修改),新来的socket连接就无法建立了。
会报:Too many open files。
二、问题分析
我回想了一下,之前在博客园上是写了一篇close_wait相关的,叫:tcp连接出现close_wait状态?可能是代码不够健壮
在那篇文章里,虽然我那也是服务端出现的,但是服务端其实是作为客户端,去调用大数据服务。严格来说,和今天遇到的场景不一样:
1、之前博客里的场景:服务端调用大数据,大数据关闭连接,(发起fin,服务器回ack)。此时,因为代码不严谨,服务端没有再向大数据发起close请求,
所以服务端与大数据的连接,在服务端上表现为close_wait。在大数据那边,状态应该是属于FIN_WAIT_2。参考下图:
2、这次遇到的场景:是作为小程序的客户端访问了服务器,服务器不知道为啥处于close_wait。
所以,一开始我也没有思路,网上查了下,有人说是tomcat 的https有bug,更多的直接教你怎么用运维手段解决。
后来,这个朋友提到,他们服务器的一个接口,是会去调用微信服务器,生成二维码,而且,他们的监控显示,该方法耗时较长。
这时,我想到一个问题是:如果服务端在处理过程中,耗时较长,(进入死循环、等锁、下游服务响应慢等),假设20s才返回,
但是客户端明显不可能等那么久,一般5-10s就超时了。超时了,客户端发起fin,服务器回ack,此时,
服务器端应该就是close_wait。
在网上搜索时,也发现网上其实有这方面案例了,比如:
我大概率估计,就是这个原因。但猜测只是猜测,还是要实践一下。
三、验证猜测
1、准备工作
我这边的一台开发服务器是windows的,装了wireshark,方便抓包,上面装了tomcat 8.5,一会直接把war包丢进去跑就完了。
我的打算是,修改目前工程的一个controller接口,让其睡眠30s再返回。 客户端的话,我用了httpclient,写了个测试类,直接去调用服务器的controller接口。
然后,用netstat观察该连接的状态变化,同时,wireshark辅助查看网络包的发送情况。
controller代码如下:
客户端代码:
pom.xml加上:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
</dependency>
工具类如下:
import com.alibaba.fastjson.JSON;
import com.ceiec.base.common.utilities.AppConstants;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.io.IOException;
import java.util.HashMap; public final class MyHttpUtils { private static int TIMEOUT = 5000; private static final String APPLICATION_JSON = "application/json"; private static final String CONTENT_TYPE_TEXT_JSON = "text/json"; private static Logger logger = LoggerFactory.getLogger(MyHttpUtils.class); /**
* POST方式提交请求
*
* @param url 请求地址
* @param json JSON格式请求内容
* @throws IOException
*/
public static String doPost(String url, String json){
if (json == null) {
HashMap<String, String> map = new HashMap<>();
json = JSON.toJSONString(map);
}
//计时
StopWatch timer = new StopWatch();
timer.start(); RequestConfig defaultRequestConfig = RequestConfig.custom().setSocketTimeout(TIMEOUT).setConnectTimeout(TIMEOUT).setConnectionRequestTimeout(TIMEOUT).build();
CloseableHttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(defaultRequestConfig).build();
HttpPost httpPost = new HttpPost(url);
httpPost.addHeader(HTTP.CONTENT_TYPE, APPLICATION_JSON);
StringEntity stringEntity = new StringEntity(json, AppConstants.UTF8);
stringEntity.setContentType(CONTENT_TYPE_TEXT_JSON);
stringEntity.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE, APPLICATION_JSON));
httpPost.setEntity(stringEntity);
httpPost.setConfig(defaultRequestConfig); CloseableHttpResponse response = null;
String responseContent = "";
try {
response = httpClient.execute(httpPost);
int status = response.getStatusLine().getStatusCode();
logger.debug("response status: " + status);
if (status >= 200 && status < 300) {
HttpEntity entity = response.getEntity();
if (entity == null) {
return null;
}
responseContent = EntityUtils.toString(entity,"UTF-8");
return responseContent;
} else {
throw new ClientProtocolException("Unexpected response status: " + status);
}
} catch (Exception e) {
logger.error("error occured.{}",e);
throw new RuntimeException(e);
} finally {
timer.stop();
logger.info("doPost. requestUrl:{}, param:{},response:{},took {} ms", url,json,responseContent,timer.getTime()); IOUtils.closeQuietly(response);
IOUtils.closeQuietly(httpClient);
}
} }
Test类:
public class Test {
public static void main(String[] args) {
MyHttpUtils.doPost("http://192.168.19.94:8080/CAD_WebService/getValue.do",null);
}
}
好了,在正式开始之前,说下MyHttpUtils中标红的那个方法:RequestConfig.custom().setSocketTimeout(TIMEOUT) 这个setSocketTimeout表示设置等待服务器端响应超时的时间,这里设为5000,意为5s
2.测试验证
这里,准备就绪了,马上开始,我们启动了服务端,然后客户端发起调用,下面是我这边的抓包(服务端视角):
这个图,咱们先看抓包:
这个包,是在服务器192.168.19.94上抓的。抓的是服务器上8080端口,和我本地pc 10.15.4.46之间的网络包。
我们分析下:
序号为1/2/3的包: 三次握手,建立连接;
序号4的包:发起http请求,请求的controller方法,会睡眠30s
序号5的包:对序号4的包的ack。注意,此时时间为14:02:11
序号6的包:此时时间已经过去5s,客户端等不及了,(就你猴急?),于是不耐烦了,老子不等了,发了个fin过来,要分手。
序号7的包:服务器说:要分手?知道了。
此时服务器在干嘛,不好意思,要睡30s,这时才睡了5s,还没醒。
说完了包,我们再看看那个cmd,里面展示的是8080端口上的连接,可以看出来,此时该连接正处于close_wait状态。
。。。
25s后。。。
25s后,服务器终于醒了,睡得不错,给客户端发响应吧(序号8),但是呢,9号包可以看出来,我的开发机给服务器回了rst。
意思就是:我不认识你。(因为前面我的开发机就提了分手。。。)
3.gif图完整回放
由于是一边写一边截图的,所以有些图等写完了再想看的时候,已经没有了。
下面截个完整的,这里,把客户端超时改为20s,方便查看:
1、服务端视角,可以看到,超时前,为established,超时后,为close_wait。
2.客户端视角
四、说到底,问题怎么解决
扯了那么多,服务器出现大量close_wait,到底怎么解决? 指标不治本的方法我就不说了,直接网上搜下,改改linux参数即可。
这篇博客主要是治本,讲了close_wait出现的一种情况:
服务端接口耗时较长,客户端主动断开了连接,此时,服务端就会出现 close_wait。
那怎么解决呢?看看代码为啥耗时长吧。
另外,如果代码不规范的话,说不定在收到对方发起的fin后,自己根本就不会给人家发fin。(比如netty自己开发的框架那种)
没啥好说的,检查自己的代码吧,反正close_wait基本就是自己这边的问题了。
如果觉得有点帮助,麻烦点个推荐哈。
ps:我这里用chrome测过,用fiddler的composer也搞过,发现有些客户端会一直等响应,过了很久才会主动去发fin,所以用了httpclient测试。
pps:tomcat在什么情况会主动发起fin?其实我也想讲讲,因为和http的connection:keep-alive这些,都有点关系,放这篇文章的话,主题就有点不集中,放下篇吧。
网络上,我也发现有些差不多场景的文章:
https://blog.csdn.net/auo67284/article/details/101102578
服务器出现大量close_wait,我们来说说到底是怎么回事?(以tomcat为例)的更多相关文章
- Web服务器讲解与JavaWeb应用部署(本机,以Tomcat为例)
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6042290.html 在讨论Web系统发布之前,我们先来辨析两个概念:服务器.Web服务器. 通常,我们说的服 ...
- 服务器TIME_WAIT和CLOSE_WAIT详解和解决办法
转载的服务器TIME_WAIT和CLOSE_WAIT详解和解决办法
- 通常每个套接字地址(协议/网络地址/端口)只允许使用一次。 数据库连接不释放测试 连接池 释放连接 关闭连接 有关 redis-py 连接池会导致服务器产生大量 CLOSE_WAIT 的再讨论以及一个解决方案
import pymysqlfrom redis import Redisimport time h, pt, u, p, db = '192.168.2.210', 3306, 'root', 'n ...
- eclipse:eclipse for java EE环境下如何配置tomcat服务器,并让tomcat服务器显示在控制台上,将Web应用部署到tomcat中
eclipse环境下如何配置tomcat 打开Eclipse,单击"Window"菜单,选择下方的"Preferences". 单击"Server& ...
- Linux服务器 大量的CLOSE_WAIT、TIME_WAIT解决办法
http://itindex.net/detail/50213-%E6%9C%8D%E5%8A%A1%E5%99%A8-time_wait-close_wait http://itindex.net/ ...
- 服务器TIME_WAIT和CLOSE_WAIT分析和解决办法
先上两张图: 查看TIME_WAIT和CLOSE_WAIT数的命令: netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a ...
- 服务器TIME_WAIT和CLOSE_WAIT区别及解决方案
系统上线之后,通过如下语句查看服务器时,发现有不少TIME_WAIT和CLOSE_WAIT. netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) ...
- 服务器环境迁移,Linux centos7 64位 基础环境部署 jdk+tomcat+mysql+nginx
最近阿里云服务器到期,这个周末连夜将服务器迁移到美国去了,为什么迁移到美国去呢?主要是因为阿里云服务器费用高,另外网站的访问量不大,对网速要求也不高,主要是宣传和信息传递的作用,加上本人之前在***上 ...
- tcp连接出现close_wait状态?可能是代码不够健壮
一.问题概述 今天遇到个小问题. 我们的程序依赖了大数据那边的服务,大数据那边提供了restful接口供我们调用. 测试反映接口有问题,我在本地重现了. 我这边感觉抓包可能对分析问题有用,就用wire ...
随机推荐
- poj 3292 H-素数问题 扩展艾氏筛选法
题意:形似4n+1的被称作H-素数,两个H-素数相乘得到H-合成数.求h范围内的H-合成数个数 思路: h-素数 ...
- PAT basic 1086
1086 就不告诉你 (15 分) 做作业的时候,邻座的小盆友问你:“五乘以七等于多少?”你应该不失礼貌地围笑着告诉他:“五十三.”本题就要求你,对任何一对给定的正整数,倒着输出它们的乘积. 输入格式 ...
- (洛谷)P1019 单词接龙
题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的"龙"(每个单词都最多在"龙" ...
- HDU 2177 取(2堆)石子游戏
取(2堆)石子游戏 Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total S ...
- service-worker实践
service-worker虽然已列入标准,但是支持的浏览器还是有限制,还有比较多的问题. 1. 生命周期 注册成功-------installing--------------> 安装成功(i ...
- linux下编译运行TIGL Viewer步骤
linux下编译运行TIGL Viewer步骤(仅为了正确编译安装的话直接跳到步骤3) 1. linux发行版选择:由于linux发行版众多,不同版本包含的库版本可能存在差别,因此需要选择正确的版本. ...
- 【Maximal Rectangle】cpp
题目: Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing all ones ...
- TOJ 3974: Region n条直线m个圆最多将圆分为几个区域
3974: Region Time Limit(Common/Java):1000MS/3000MS Memory Limit:65536KByteTotal Submit: 33 ...
- ls 的顺序与倒序排列
linux 中文件夹的文件按照时间倒序或者升序排列 1,按照时间升序 ls -lrt -l use a long listing format 以长列表方式显示(详细信息方式) -t sort by ...
- Log4j官方文档翻译(七、日志格式化)
apache log4j提供各种layout对象,然后根据自己指定的layouts对象转化日志信息.通常来说都是应用量身定制layout对象转换信息格式. 所有的layout对象从Appender对象 ...