• 记录一个HttpClient超时连接配置不生效的问题排查过程


    现象

    首先有一个被服务由于内存有限,导致巨卡。导致调用他的服务出现线程阻塞。jstack打印线程池如下所示:

    开始排查解决问题

    第一步:检查代码看是否超时设置是否正确,因为感觉超时设置正确不可能阻塞。

    找到注入client的位置:

    发现配置没有任何问题,此时感到了一点点慌张。(内心OS: 难不成HttpClient还有BUG, 讲道理这么成熟的框架不应该啊)

    第二步:本着高效的原则,百度一下是否有其他人踩过这样的坑了。

    咦,这不和遇到的一样吗? 心想搞定。看我jstack栈阻塞堆栈信息,也是有重试的信息,如下图所示:

    那么直接更改我们的client注入代码为如下:

    以为到这里故事就结束了,开开心心重新部署一下,就去玩其他的了。

    噩梦再次上演:几天后,被调用服务再次出现卡顿,然后调用方又阻塞了,what fuck !

    老规矩看堆栈信息:

    还是熟悉的配方,一样的错误,阻塞在同一个地方。本着高效的原则,GPT了一下,然并没有什么用,都是一些太泛的思路,这玩意干精细活还是有缺陷:

    那这样的话,就苦逼了,只能慢慢的撸他源码了。因为服务器卡顿是偶现,还没法调试。找到构建过程如下:

    显然实际执行在InternalHttpClient里面。点进去看一下他的执行过程:

    发现我们配置的requestConfig可能并未生效,他可能直接从Request里面取,那这显然有可能在调用方给Request手动配置requestConfig。 找到调用处的代码:

    显然确实有可能是这个原因,那有了上次的经验,我们要验证一下。由于服务器卡顿是偶现,我们debug看一下是不是走到这里了:

    发现都是-1, 那应该就是这个问题了,Request配置,重新打包部署,问题再也没有复现过。over!

    题外话

    源码定位问题的过程省略了很多,所以看起来解决问题过程似乎很简单。因为框架代码毕竟那么多,我第一步先是猜想要先定位到他超时判断逻辑的代码在哪里,才能知道为什么不生效。定位了很久才发现框架本身并无相关逻辑,他是构建了一个Socket去请求,在socket中有两个时间,一个是soTimeOut(读流超时时间), 一个是connectTimeOut(连接超时时间)。 其在创建socket的时候需要指定connectTimeOut,然后soTimeOut可在发起请求前设置。 当然这也反应出分析问题不够冷静, 忽略了基本的网络常识,这些成熟的框架,一开始就应该思考是不是配置不正确的问题,究其原因也是对框架不够深入了解,不知道具体的某个请求可能还存在可以配置单独的RequestConfig对象,一味的关注CloseableHttpClient的配置去了。

  • 相关阅读:
    回忆三年浮沉
    U-net详解
    平板用电容笔还是触控笔?双十一值得买电容笔推荐
    【算法与数据结构】--高级算法和数据结构--高级数据结构
    基础架构之分布式配置中心
    uniapp项目实践总结(十三)封装文件操作方法
    操作系统:2.3.2实现临界互斥的基本方法
    【数据结构】二叉树(定义、性质、存储、遍历、构造)解析+完整代码
    去耦电路设计应用指南(一)MCU去耦设计介绍
    数据库概论 - MySQL的简单介绍
  • 原文地址:https://www.cnblogs.com/enjoyall/p/18159220