一次接口偶发超时的排查记录:从线程池打满到 TCP 连接复用

举报
yd_264617019 发表于 2026/10/16 21:32:51 2026/10/16
【摘要】 上周三下午,订单查询接口的告警群突然热闹起来:P99延迟从平时的80ms抬升到3秒以上,而且每过十几分钟就抖一次,持续一两分钟又自己恢复。这种"间歇性抖动"最烦人,平均延迟看起来还算正常,监控大盘一片绿,只有P99曲线在反复横跳。第一反应:看错监控大盘反而被误导先看了QPS和错误率,都没有明显变化,说明不是流量突增。再看应用GC,YoungGC频率正常,FullGC一次都没有。CPU使用率4...

上周三下午,订单查询接口的告警群突然热闹起来:P99 延迟从平时的 80ms 抬升到 3 秒以上,而且每过十几分钟就抖一次,持续一两分钟又自己恢复。这种"间歇性抖动"最烦人,平均延迟看起来还算正常,监控大盘一片绿,只有 P99 曲线在反复横跳。

第一反应:看错监控大盘反而被误导

先看了 QPS 和错误率,都没有明显变化,说明不是流量突增。再看应用 GC,Young GC 频率正常,Full GC 一次都没有。CPU 使用率 40% 左右,远没到瓶颈。到这里基本可以排除"资源不够"这类最常见的原因。

真正有价值的线索来自线程 dump。让运维连抓了 5 次线程栈,间隔 10 秒,其中两次正好落在抖动窗口里。对比后发现:抖动时 http-nio-8080-exec 线程全部处于 WAITING,栈顶停在 org.apache.http.pool.AbstractConnPool.lease——这是 HttpClient 在等连接池归还连接。

复盘连接池配置

把 HttpClient 的连接池配置翻出来看:

PoolingHttpClientConnectionManager cm =
        new PoolingHttpClientConnectionManager();
cm.setMaxTotal(200);            // 全局连接上限
cm.setDefaultMaxPerRoute(20);   // 单路由上限,默认只有 2!

RequestConfig rc = RequestConfig.custom()
        .setConnectTimeout(1000)
        .setSocketTimeout(3000)
        // 关键:从池里借连接的等待上限
        .setConnectionRequestTimeout(3000)
        .build();

问题很典型:这个服务依赖的下游只拆了两个域名,单路由 20 个连接,正常情况下够用。但订单查询下游有个"热点用户"效应——大客户轮询拉单,一秒钟能打过来上百个并发,瞬时把单路由的 20 个连接全部占满,后续请求就在 lease 上排队,最多等 3 秒。这正好解释了为什么 P99 抖到 3 秒上下、又会在流量峰过去后自愈。

修复:分层限流 + 连接池调参

只调大连接池是治标,下游扛不住更大的并发反而更危险。最终做了三件事:

  1. 单路由连接从 20 提到 50,connectionRequestTimeout 降到 800ms,宁可快速失败也不 hang 住业务线程;
  2. 对热点用户的查询加本地 Caffeine 缓存,TTL 5 秒,同类请求合并回源;
  3. 网关层对该客户加 50 QPS 的限流,超额直接返回缓存快照。

改完压测:单路由并发 100 时 P99 稳定在 240ms,连接池借用的等待时间分布(通过 Micrometer 的 httpclient.pool 指标)P99 只有 6ms。

一个容易忽略的坑:连接不复用

压测复验时又发现一个次生问题——长稳跑 10 分钟后,TIME_WAIT 数量涨到四万多。抓包看是每次请求都新建了 TCP 连接。原因是响应头里下游返回的是 Connection: close,而且我们自建 HttpClient 时没有显式开启 keep-alive 策略。补上默认的 keep-alive 并让连接池定期驱逐空闲连接:

cm.setValidateAfterInactivity(2000);  // 空闲 2s 后先校验再复用

顺带在内核层开了 tcp_tw_reuse,TIME_WAIT 回落到一万以内。

小结

排查这类"偶发抖动",最有效的动作往往是在抖动窗口内抓线程栈,静态配置和监控大盘都容易骗人。连接池参数里 defaultMaxPerRoute 默认值只有 2,很多团队都是踩过一次才记住。给连接池加上租借等待时长的指标,是提前发现这类问题的性价比最高的手段。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。