Skip to content

针对线上接口响应慢的问题,以下是一套系统化的排查流程和具体操作指南,涵盖从基础设施到代码层的全链路分析:


一、快速确认问题范围

  1. 检查是否突发性异常

    bash
    # 查看最近1小时流量变化
    cat access.log | awk '{print $4}' | cut -d: -f2 | sort | uniq -c
    • 流量突增(如DDoS)可能导致系统过载
    • 特定时间段触发定时任务(如报表生成)
  2. 区分全局问题与局部问题

    • 全局问题:所有接口响应慢 → 检查系统资源、中间件、网络
    • 局部问题:特定接口慢 → 检查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'

六、防御性架构设计

  1. 服务降级
    • 配置Hystrix熔断规则:在超时率>50%时自动熔断
  2. 限流保护
    java
    // 使用Guava RateLimiter控制QPS
    RateLimiter limiter = RateLimiter.create(1000); // 每秒1000请求
    if (!limiter.tryAcquire()) {
        throw new RateLimitException();
    }
  3. 异步化改造
    java
    // 将同步调用改为CompletableFuture
    CompletableFuture.supplyAsync(() -> externalService.call(), executor)
        .exceptionally(ex -> fallbackResult);

问题定位流程图

开始  

├─ 是否所有接口都慢?  
│   ├─ 是 → 检查系统资源/中间件/网络  
│   └─ 否 → 定位到具体接口  

├─ 数据库层面:  
│   ├─ 慢SQL分析  
│   └─ 连接池是否耗尽?  

├─ 缓存层面:  
│   ├─ 缓存命中率是否骤降?  
│   └─ Redis内存是否打满?  

├─ JVM层面:  
│   ├─ Full GC是否频繁?  
│   └─ 线程是否死锁?  

└─ 代码层面:  
    ├─ 是否存在循环依赖查询?  
    └─ 同步锁是否过度竞争?  
结束

通过以上系统化的排查流程,可以快速定位到90%以上的性能瓶颈。实际场景中建议结合APM工具(如SkyWalking、PinPoint)实现自动化监控。

文章来源于自己总结和网络转载,内容如有任何问题,请大佬斧正!联系我