针对线上接口响应慢的问题,以下是一套系统化的排查流程和具体操作指南,涵盖从基础设施到代码层的全链路分析:
一、快速确认问题范围
检查是否突发性异常
bash# 查看最近1小时流量变化 cat access.log | awk '{print $4}' | cut -d: -f2 | sort | uniq -c
- 流量突增(如DDoS)可能导致系统过载
- 特定时间段触发定时任务(如报表生成)
区分全局问题与局部问题
- 全局问题:所有接口响应慢 → 检查系统资源、中间件、网络
- 局部问题:特定接口慢 → 检查SQL/缓存/第三方服务调用
二、基础设施层排查
1. 系统资源监控
bash
# 实时查看系统负载(重点关注%wa表示I/O等待)
top
# 每2秒刷新一次,观察CPU、内存、中断
vmstat 2
# 查看磁盘I/O情况(注意%util和await)
iostat -x 1
# 网络带宽监控(关注RX/TX是否打满)
nload -m
关键指标:
- CPU使用率 >70%(需关注用户态占比)
- 内存Swap使用 >0(可能触发OOM)
- 磁盘%util >90%或await >50ms(存在I/O瓶颈)
- 网络带宽占用 >80%
2. 网络链路排查
bash
# 测试DNS解析延迟
dig +short 你的域名 | xargs -I{} ping -c 4 {}
# 全链路时延检测(展示每跳延迟)
mtr -rw 目标IP
# 抓包分析网络丢包/重传
tcpdump -i eth0 -w slow.pcap
三、中间件层排查
1. 数据库慢查询
sql
-- MySQL开启慢查询日志(需提前配置)
SHOW VARIABLES LIKE 'slow_query_log%';
-- 实时查看活跃SQL(重点关注Rows_examined高语句)
SELECT * FROM information_schema.processlist WHERE TIME > 5;
2. 缓存异常
bash
# Redis监控
redis-cli info | grep -E '(used_memory|expired_keys|evicted_keys|connected_clients)'
# 检查缓存命中率(低于90%需排查)
redis-cli info stats | grep keyspace
3. 消息队列堆积
bash
# Kafka查看堆积量
kafka-consumer-groups.sh --describe --group 你的消费组
# RabbitMQ检查队列深度
rabbitmqctl list_queues name messages_ready
四、应用层排查
1. 线程池状态分析
bash
# 查看Tomcat线程池(关注maxThreads是否打满)
curl -s 127.0.0.1:8080/actuator/metrics/tomcat.threads.busy?tag=name:http-nio-8080
# 使用Arthas实时监控线程阻塞
thread -n 5 # 显示CPU占用前5线程
thread -b # 检测死锁
2. JVM性能分析
bash
# 查看GC情况(关注Full GC频率)
jstat -gcutil <pid> 1000
# 生成堆转储文件(分析内存泄漏)
jmap -dump:live,format=b,file=heap.hprof <pid>
# 实时火焰图(定位CPU热点)
arthas profiler start -d 30 --event cpu
3. 慢请求追踪
java
// 在代码中添加埋点(示例)
long start = System.currentTimeMillis();
try {
// 业务逻辑
} finally {
long cost = System.currentTimeMillis() - start;
if (cost > 500) { // 记录超过500ms的请求
logger.warn("Slow request detected: {}ms, params={}", cost, params);
}
}
五、代码层深度优化
1. **常见性能陷阱
循环依赖查询(N+1查询问题)
java// 错误示例:在循环中查询DB for (Order order : orderList) { User user = userRepository.findById(order.getUserId()); // 触发多次查询 } // 优化:改为批量查询 List<Long> userIds = orderList.stream().map(Order::getUserId).toList(); Map<Long, User> userMap = userRepository.findByIds(userIds).stream() .collect(Collectors.toMap(User::getId, Function.identity()));
不合理的锁竞争
java// 错误示例:粗粒度锁导致并发度下降 synchronized(this) { // 业务逻辑 } // 优化:使用细粒度锁(如ConcurrentHashMap分段锁)
大量对象创建
java// 避免在循环内创建SimpleDateFormat等重量级对象 private static final ThreadLocal<SimpleDateFormat> dateFormat = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
2. 压测验证
bash
# 使用wrk模拟并发请求
wrk -t12 -c400 -d30s --latency http://your-api
# 结合Arthas观察方法耗时
trace com.example.Controller * '#cost>200'
六、防御性架构设计
- 服务降级
- 配置Hystrix熔断规则:在超时率>50%时自动熔断
- 限流保护java
// 使用Guava RateLimiter控制QPS RateLimiter limiter = RateLimiter.create(1000); // 每秒1000请求 if (!limiter.tryAcquire()) { throw new RateLimitException(); }
- 异步化改造java
// 将同步调用改为CompletableFuture CompletableFuture.supplyAsync(() -> externalService.call(), executor) .exceptionally(ex -> fallbackResult);
问题定位流程图
开始
│
├─ 是否所有接口都慢?
│ ├─ 是 → 检查系统资源/中间件/网络
│ └─ 否 → 定位到具体接口
│
├─ 数据库层面:
│ ├─ 慢SQL分析
│ └─ 连接池是否耗尽?
│
├─ 缓存层面:
│ ├─ 缓存命中率是否骤降?
│ └─ Redis内存是否打满?
│
├─ JVM层面:
│ ├─ Full GC是否频繁?
│ └─ 线程是否死锁?
│
└─ 代码层面:
├─ 是否存在循环依赖查询?
└─ 同步锁是否过度竞争?
结束
通过以上系统化的排查流程,可以快速定位到90%以上的性能瓶颈。实际场景中建议结合APM工具(如SkyWalking、PinPoint)实现自动化监控。