Administrator 7 阅读 面试

慢接口排查思路

慢接口排查思路(口述版)


面试口述版(优先背这个)

一个接口变慢,我一般不会先改代码,而是按「先定位、再分层、后优化」来排查。

第一步:先确认慢在哪。 先分清是前端慢、网关慢,还是后端接口本身慢。看接口总耗时、QPS、错误率,对比是个别用户慢,还是全量慢;是偶发,还是持续。如果有链路追踪(SkyWalking、Pinpoint、Zipkin),先看整条调用链,哪一段耗时最长,基本就能圈定范围。

第二步:按调用链路一层层拆。 一个请求通常经过:网关 → 应用服务 → 缓存 / 数据库 / 下游 RPC / 消息队列。我会把耗时拆开:

  • 网关到应用的网络和排队时间
  • 应用内部业务逻辑时间
  • 数据库 SQL 时间
  • Redis 等缓存时间
  • 下游接口时间

哪一层占比最大,就先查哪一层。

第三步:应用层常见问题。 看线程池是否打满、有没有锁等待、有没有同步调用外部接口、有没有一次性加载太多数据、有没有循环里查库(N+1)。必要时抓线程栈(jstack)看线程都卡在什么方法上。

第四步:数据库往往是重灾区。 打开慢 SQL 日志,对可疑 SQL 做 EXPLAIN。重点看有没有全表扫描、有没有走错索引、有没有深分页、有没有大事务、有没有锁等待。很多慢接口最后都是一条慢 SQL 或一次回表过多。

第五步:缓存和下游。 看 Redis 是否命中率低、是否有大 Key、是否发生了缓存穿透/击穿。下游接口如果慢,要看超时设置、是否可以异步、是否需要降级或批量调用。

第六步:确认优化效果。 改完后对比优化前后的 RT、P99、错误率,避免只优化了平均值、长尾依然很慢。

一句话总结:
先用监控和链路追踪定位慢在哪一层,再针对应用、数据库、缓存、下游分别处理,最后用数据验证。


详细排查清单

1. 先定性:慢到什么程度、谁在慢

问题 目的
是页面慢还是接口慢? 排除前端渲染、静态资源
是某一个接口慢,还是一批接口都慢? 判断是单点问题还是整体负载
是偶发还是持续?高峰才慢? 判断容量、锁、GC、慢 SQL
P99 / P999 还是平均 RT 高? 平均低、长尾高,往往是个别慢 SQL 或外部依赖
是否伴随超时、500、线程池拒绝? 判断是否已经打满

常用工具:Nginx / 网关日志、Prometheus、Grafana、APM、SkyWalking。


2. 按链路拆耗时

客户端
  → 网关 / Nginx
    → 应用服务器(Controller / Service)
      → Redis
      → MySQL
      → 下游 HTTP / RPC
      → 消息队列

每一段都要能回答:这段花了多少毫秒。

  • 网关慢:连接排队、限流、鉴权、带宽
  • 应用慢:业务逻辑、序列化、锁、线程池排队、GC
  • DB 慢:SQL、索引、锁、连接池不够
  • 缓存慢:网络、大 Key、热 Key、穿透
  • 下游慢:对方 RT 高、超时设置不合理、同步串行调用

3. 应用层怎么查

重点看这几件事:

  1. 线程池有没有满
    Tomcat / 业务线程池队列堆积,请求在排队,接口就会变慢。
  2. 有没有同步堵在外部调用
    一个接口里串行调 3、4 个下游,每个 200ms,加起来就接近 1 秒。
  3. 有没有循环查库 / 循环调接口
    典型 N+1:查 100 条订单,再循环查 100 次用户。
  4. 有没有大对象序列化、大结果集一次性返回
  5. GC 是否频繁
    Full GC 时接口会集体卡顿。
  6. 锁竞争
    synchronized / 分布式锁粒度太大,线程都在等锁。

常用手段:

  • 看应用日志里的方法耗时
  • jstack 看线程卡在哪
  • Arthas trace / watch 定位热点方法
  • 看 GC 日志、线程池监控

4. 数据库怎么查(最常见)

排查顺序:

  1. 慢查询日志找出耗时 SQL
  2. EXPLAIN 看执行计划
  3. 看扫描行数、是否走索引、是否 filesort / temporary
  4. 看有没有锁等待、死锁、长事务
  5. 看连接池是否耗尽(Druid / Hikari 监控)

常见原因和对应优化:

原因 优化
没索引 / 索引失效 加索引,避免对索引列套函数
深分页 limit 100000,10 延迟关联或按上一页最大 ID 翻页
SELECT * 回表多 只查需要字段,覆盖索引
一次性查太多 分页、限制返回条数
大事务 / 锁等待 缩短事务,避免在事务里调远程
连接池不够 调大连接池,同时优化 SQL 减少占用时间

5. 缓存和下游怎么查

缓存:

  • 命中率是否下降
  • 是否大 Key、热 Key
  • 是否穿透、击穿、雪崩
  • Redis 本身是否慢(bigkey、CPU、网络)

下游:

  • 下游 RT 本身高
  • 没有超时,把线程拖死
  • 可以并行的却串行调用
  • 可以异步 / 消息队列的却同步等待

优化方向:超时 + 重试(有限次)+ 降级 + 并行(CompletableFuture)+ 批量接口。


6. 一个可直接说的排查顺序(面试很好用)

  1. 看监控:接口 RT、QPS、错误率、P99
  2. 看链路追踪:定位最慢的 span
  3. 如果是 SQL:慢日志 + EXPLAIN
  4. 如果是应用:线程栈 + 方法耗时 + 线程池
  5. 如果是下游:看对方 RT、超时、是否可异步
  6. 如果是缓存:命中率、大 Key、穿透
  7. 优化后对比 P99,确认长尾也降下来

项目里可以这样举例

「有一次列表接口 P99 到了 2 秒。链路追踪发现 80% 时间在一条订单查询 SQL 上。EXPLAIN 显示没走索引,原因是对时间字段用了函数,索引失效。加上合适索引,并把循环查用户改成一次 IN 查询后,P99 降到 200ms 以内。」

这种「现象 → 定位工具 → 根因 → 优化结果」的叙述最加分。


一句话收尾

慢接口排查不是上来改代码,而是:

监控确认 → 链路拆分 → 定位最慢一层 → 针对优化 → 用 P99 验证。