• 13
  • 13
分享
  • 服务器HttpClient连接池耗尽问题排查与解决——软件测试圈
  • 曼倩诙谐 2021-07-22 10:47:14 字数 2162 阅读 3058 收藏 13

  问题情景

  服务器重新部署应用后,运行一段时间后,某一微服务开始出现错误提示:连接超时:服务忙,导致相关功能无法正常使用。

  问题排查

  日志查看

  首先下载对应服务的日志查看报错内容,日志中出现了很多org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool 的异常信息。可以看出日志中的错误定位在HttpClient连接池,连接超时可能是连接池连接耗尽,没有可用连接导致无法正常获取连接提供服务。

  初步猜想

  HttpClient连接池中为了防止连接被长期占用会设置超时时间,如果超时时间设置的不合理,比较长,而服务中的某些连接请求时间又很长的时候,会导致连接被长期占用不被释放,最终导致HttpClient连接池耗尽。如果初步猜想成立的话那么其他提供服务的机器应该也会出现这个问题,但是根据其他机器的日志分析来看,它们并没有出现连接池耗尽的情况,问题只出现在单个机器上。

  定点分析

  通过日志分析出问题出现在单个机器上,我们就登录该服务器查看服务器中连接池中各个连接的状态。可以通过 netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' 命令对各种状态的连接分组查看,结果如下图所示,可以看到有很多处于CLOSE_WAIT状态的连接,数据与我们在项目中配置的连接池最大数量一致,因此可以判断是有大量未关闭的连接占满了连接池,导致连接池耗尽无法提供正常连接。

1.png

图 1 连接状态分组结果

  提到CLOSE_WAIT状态,我们就需要知道TCP的状态转移是如何进行的。通过下图我们可以分析得到,在被动关闭连接情况下,在已经接收到FIN,但是还没有发送自己的FIN的时刻,连接处于CLOSE_WAIT状态。通常来讲,CLOSE_WAIT状态的持续时间应该很短,正如SYN_RCVD状态。但是在一些特殊情况下,就会出现连接长时间处于CLOSE_WAIT状态的情况。出现大量close_wait的现象,主要原因是某种情况下对方关闭了socket链接,但是我方忙与读或者写,没有关闭连接。

2.png

图2 TCP状态转移图

  问题定位

  分析出具体的连接池耗尽原因后我们需要找到对应的代码。根据日志中出现的连接超时信息可以找到抛出该异常的错误代码位置,代码如下:

public void getResources(String url) {
    LogUtils.info("Get URL={}", url);
    CloseableHttpClient httpclient = HttpClients.createDefault();
    HttpGet httpGet = new HttpGet(url);
 
    try {
        CloseableHttpResponse response1 = httpclient.execute(httpGet);
        HttpEntity entity1 = response1.getEntity();
        // 一些业务操作
        EntityUtils.consume(entity1);
    } catch (Exception e) {
        LogUtils.error("Get error", e);
    }
}

  可以看到代码中对response做完操作之后并没有进行关闭,导致数据流中有一个结束符EOF一直没有被接收,从而连接一直被占用。

  修复问题

  问题定位后,我们就要修复问题,对于返回回来的流我们获取数据做完操作之后应该及时关闭,所以按照这个思路进行了改动。

public void getResources(String url) {
    LogUtils.info("Get URL={}", url);
    CloseableHttpClient httpclient = HttpClients.createDefault();
    HttpGet httpGet = new HttpGet(url);
    CloseableHttpResponse response1 = httpclient.execute(httpGet);
    try {
        HttpEntity entity1 = response1.getEntity();
        // 一些业务操作
        EntityUtils.consume(entity1);
    } finally {
        response1.close();
    }
}

  总结

  出现CLOSE_WAIT的根本原因是应用端未关闭一个已经被对端关闭的连接导致,在出现该问题时,我们可以通过netstat等命令查看tcp的对端和端口,从而定位出现问题的地方并进行修改。还有就是平时进行流处理操作时需要及时关闭流,释放资源,避免后续资源死锁。



作者:谢远辉   

来源:51Testing软件测试网原创

  • 【留下美好印记】
    赞赏支持
登录 后发表评论
+ 关注

热门文章

    最新讲堂

      • 推荐阅读
      • 换一换
          • Python是一门非常简洁的语言,和c/c++,java等有着较大的差别。到list和tuple这儿有点犯迷糊了,就从这儿开始写起。目前做接触到的列表有4个,dicth和set,这篇文章就来看看这几种列表的特性和用法。一、python“数组”ListList是python内置的一种数据类型列表。在我看来有点类似于数组,但是深究下来却有很多不同。题外话:python和以往学过的编程语言最大的不同在于变量不用声明类型,也就是可以实现如下操作:a = 3 print(a) a = ‘s’ print(a)这样的操作在大多数在以前学过的三种语言种都是不合法的,但...
            14 14 4011
            分享
          •   有一份51Testing测试行业调查问卷需要您的助力,差不多三分钟的时间即可填完。我们给您准备了一份价值398元的测试课程作为礼品,感谢您的帮忙~链接:http://vote.51testing.com/  前言  最近是跳槽季,发现有小伙伴在一些非技术的软性问题上答的不是很好。  众所周知,程序员情商偏低,而这些软性问题,恰恰都具有一定欺骗性和吹牛皮成分在里边,对于演技不好的直男癌,简直就是天生克星。  其实不用太担心,软性问题往往就那几个,稍加训练和准备,你就可以成为一位高端名猿。  题目  第 1 题:说一下你自己的缺点  演技考验:4星  这题处处暗藏杀鸡,很多小伙伴会推心置腹,诚...
            0 0 1291
            分享
          • 常用的Android自动化测试框架包括UIAutomator、Appium以及Monkeyrunner等;其中,UIAutomator是谷歌在发布Android4.1版本时推出的一款基于Java语言的UI测试框架,由此,UIAutomator只能运行在4.1及其以上版本中。本篇文章将为大家介绍如何搭建基于Java+UIAutomator的测试环境。一、UIAutomator简介首先,作为Google自家推出的一款开源的UI自动化测试框架,其稳定性和可靠性可以得到极大的保障,运行时也有更多的权限。其次,UIAutomator可以跨进程操作,运行速度较快;但是UIAutomator不支持Andro...
            0 3 2952
            分享
          • 读者提问:阿常你好,请问测试如何给开发提每年或每个季度的产品/项目质量目标,由测试提出,作为开发部门的目标,从而控制开发的质量 ?阿常回答:你们之前应该没有做过这类工作,所以你想参考下其他公司的做法对吗?阿常之前也没有给开发定过质量相关的指标,但可以给你一些建议,你看看是否能够参考一二:每个开发负责不同的产品/项目,项目本身复杂程度的不同,以及所处阶段的不同都会影响最终产生bug的数量多少和严重等级高低。所以参与不同项目的开发不能制定同一个质量标准。你可以记录一段时间每个项目的实际质量情况,再据此对每一个项目做质量目标的制定。比如说对产品A的版本1~版本10进行质量情况的统计,看看目...
            0 0 1159
            分享
      • 51testing软件测试圈微信