跳到主要内容

接口超时排查

问题

线上接口 RT 突然从 100ms 飙升到 5s,甚至超时,如何排查?

答案

排查思路

第一步:确定慢的范围

日志分析
# 看最近 1 小时哪些接口超时最多
grep "timeout\|timed out" app.log | awk '{print $5}' | sort | uniq -c | sort -rn | head 20

第二步:链路追踪定位

通过 SkyWalking / Zipkin / Jaeger 查看请求链路,看 Span 耗时:

链路追踪结果
OrderController.createOrder             5200ms  ← 总耗时
├─ OrderService.checkInventory 50ms ← 正常
├─ OrderMapper.insert 80ms ← 正常
├─ PaymentClient.createPayment 4800ms ← 这里慢!
│ └─ HTTP POST /api/payment 4800ms
└─ OrderMapper.updateStatus 20ms

定位到问题出在下游支付服务调用。

第三步:按方向深入排查

方向 1:数据库慢

排查慢 SQL
// 检查慢查询日志(见慢 SQL 排查)
// 检查连接池是否打满
HikariPoolMXBean poolProxy = ((HikariDataSource) dataSource).getHikariPoolMXBean();
log.info("Active: {}, Idle: {}, Waiting: {}",
poolProxy.getActiveConnections(),
poolProxy.getIdleConnections(),
poolProxy.getThreadsAwaitingConnection());

方向 2:Redis 慢

Redis 排查
# 查看慢查询日志
redis-cli slowlog get 10

# 查看大 Key
redis-cli --bigkeys

# 查看连接数
redis-cli info clients

方向 3:下游服务超时

Feign 超时设置
feign:
client:
config:
payment-service:
connect-timeout: 2000 # 连接超时 2s
read-timeout: 5000 # 读超时 5s

# 配合熔断
resilience4j:
circuitbreaker:
instances:
payment:
failure-rate-threshold: 50
slow-call-duration-threshold: 3s

方向 4:线程池/连接池打满

线程池耗尽的典型表现
所有请求排队等待 → RT 急剧上升
日志出现 RejectedExecutionException
Tomcat 线程全部 WAITING / TIMED_WAITING
Tomcat 线程池监控
# application.yml
server:
tomcat:
threads:
max: 200 # 最大线程数
min-spare: 20 # 最小空闲
max-connections: 8192
accept-count: 100 # 等待队列

优化策略

策略说明
超时设置每一层调用都设合理超时
熔断降级下游超时触发熔断,快速失败
缓存热点数据缓存,减少下游调用
异步化非核心链路异步处理
连接池调优合理配置数据库/HTTP/Redis 连接池
预热服务启动后预热缓存和连接池

常见面试问题

Q1: 排查接口慢的完整思路?

答案

  1. 看监控:CPU、内存、GC、连接池水位
  2. 看链路追踪:找到慢的 Span
  3. 分方向深入:DB 慢查询 / Redis 大 Key / 下游超时 / 线程池满
  4. 优化:加索引 / 加缓存 / 加超时 / 加熔断

Q2: 超时时间怎么设置合理?

答案

  • 参考历史 P99 延迟,设置为 P99 的 2-3 倍
  • 链路超时层层递减:网关 > 调用方 > 被调方
  • 例:网关 10s → A 服务调 B 5s → B 调 DB 2s

Q3: 所有接口同时变慢,最可能的原因?

答案

  • Full GC:STW 导致所有请求暂停
  • CPU 100%:线程切换增多,处理变慢
  • 连接池打满:所有请求排队等连接
  • 网络故障:带宽打满或网络抖动

相关链接