跳至主要內容

Java 接口突然变慢,我通常先检查哪 5 个位置

布衣云水客大约 6 分钟文章JavaJavaSpring Boot性能优化JVM数据库

概要

“这个接口昨天还是 200ms,今天突然变成 5 秒。”

遇到这类问题,最危险的做法是立即改线程池、加缓存或者重启服务。它们有时能暂时缓解问题,却可能掩盖真正原因,并给系统引入新的不确定性。

我做过中台慢接口治理、性能边界压测和高并发服务调优。面对接口变慢,我通常按照“先界定范围,再沿调用链缩小问题”的方式排查,重点检查以下五个位置。

一、先确认“慢”发生在哪里

第一步不是看代码,而是建立事实:

  • 是平均耗时变慢,还是 P95/P99 尾延迟变慢?
  • 是所有请求都慢,还是某类参数、租户或数据范围慢?
  • 是单个实例慢,还是所有实例慢?
  • 从什么时间开始?期间是否有发布、配置、数据量或流量变化?
  • 服务端处理慢,还是网关排队、客户端网络或重试造成的慢?

至少把一次请求拆成:

客户端耗时
  = 网络与网关
  + 应用排队
  + 业务计算
  + 数据库/缓存
  + 下游调用
  + 序列化与响应传输

如果系统已有 Trace,先找到慢请求的完整 Span;如果没有,至少通过网关日志、应用访问日志和业务关键节点日志对齐同一个请求 ID。

二、检查数据库:最常见,但不能只看“有没有慢 SQL”

数据库问题通常包括四类。

1. 执行计划发生变化

相同 SQL 可能因为数据分布、统计信息、参数或索引变化,突然选择了不同的执行计划。重点关注:

  • 是否从索引扫描退化为全表扫描;
  • 联表顺序是否改变;
  • 估算行数与实际行数是否严重偏离;
  • 排序、临时表和回表次数是否异常。

2. 查询范围悄悄扩大

代码没有变化,但数据量在增长。例如默认查询最近 30 天,某个条件失效后变成查询全量;分页仍然存在,但为了计算总数执行了一次昂贵的 count

3. 锁等待和长事务

SQL 本身执行很快,不代表请求不会慢。事务中夹杂远程调用、批量循环或大量业务计算,可能长时间占用连接和锁。

4. 连接池排队

应用监控中数据库耗时不高,但获取连接已经等待了几秒。需要同时观察连接池活跃数、等待线程、超时数和数据库连接上限。

三、检查下游调用:一次变慢可能被重试放大

一个接口经常要调用多个微服务、第三方接口或消息组件。某个下游偶发超时后,如果上游配置了多层重试,实际耗时可能变成:

3 次客户端重试 × 2 次网关重试 × 单次 1 秒超时

最终用户看到的就不再是 1 秒,而可能是数秒甚至更长。

排查时重点看:

  • DNS、连接建立、TLS、首包和响应读取分别耗时多少;
  • 超时设置是否分层且合理;
  • 是否存在客户端、网关和业务代码重复重试;
  • 熔断、限流和降级是否真正生效;
  • 并行调用是否因为一个慢节点退化成整体等待。

重试不是免费的可靠性。对非幂等操作,错误重试还可能造成重复写入。

四、检查 JVM 和线程池:CPU 不高也可能严重阻塞

很多人只看 CPU 和内存使用率。实际上,即使 CPU 不高,请求也可能因为线程排队、锁竞争或 GC 停顿而变慢。

线程池

需要观察:

  • 活跃线程数与最大线程数;
  • 队列长度和拒绝次数;
  • 任务平均执行时间;
  • 是否把阻塞 I/O 和 CPU 计算混在同一个池中;
  • 是否出现线程池之间相互等待。

线程池不是越大越好。线程增加可能带来更多上下文切换、数据库连接争抢和下游压力。

JVM

重点关注:

  • Young GC、Full GC 的频率与停顿;
  • 堆内存增长是否与流量匹配;
  • 大对象、缓存和集合是否异常增长;
  • 是否存在大量锁等待、死锁或 Safepoint 停顿;
  • 日志、JSON 序列化、正则表达式等 CPU 热点。

在生产环境抓取线程栈或堆信息前,应先评估开销,优先使用低风险的监控和采样手段。

五、检查应用自身:缓存、日志、数据结构和发布变化

最后回到应用内部,但不要直接通读全部代码,而是围绕慢 Trace 检查:

  • 缓存是否失效、击穿或集中到期;
  • 是否出现 N+1 查询;
  • 循环中是否调用数据库或远程接口;
  • 日志级别是否被调整,是否同步输出大量内容;
  • 返回对象是否突然增大;
  • 新增切面、鉴权、审计或序列化逻辑是否进入主链路;
  • 配置中心是否下发了不同于发布包的配置。

一次发布包含几十个改动时,优先做版本、配置和实例之间的差异对比,比“凭经验猜代码”更有效。

我的排查顺序

修复后至少对比吞吐量、P95/P99、错误率、资源使用和下游压力。只看到平均耗时下降,并不能说明问题已经解决。

结语

性能排查的本质不是记住几十条 JVM 参数,而是快速建立证据链:哪里慢、为什么慢、改动是否真正消除了瓶颈、系统边界是否发生转移。

我目前接受少量 Java/Spring Boot 系统的远程性能诊断、架构体检和疑难问题分析。可以先从单个慢接口或一次短期诊断开始,交付问题证据、风险优先级和整改建议。