接口性能排查指南

一、排查流程总览

性能排查流程图:
┌─────────────────────────────────────────────────────────────────┐
│                    接口响应慢                                    │
│                            ↓                                    │
│              ┌────────────────────────────────┐                 │
│              │       1. 确认问题范围          │                 │
│              │    - 单个接口 vs 全局          │                 │
│              │    - 特定用户 vs 全部用户       │                 │
│              └────────────┬───────────────────┘                 │
│                           ↓                                     │
│              ┌────────────────────────────────┐                 │
│              │       2. 四维度排查            │                 │
│              │    ┌─────┬─────┬─────┬─────┐   │                 │
│              │    │ JVM │ SQL │ 网络 │ 线程 │   │                 │
│              │    │ GC  │     │ I/O  │ 池   │   │                 │
│              │    └─────┴─────┴─────┴─────┘   │                 │
│              └────────────┬───────────────────┘                 │
│                           ↓                                     │
│              ┌────────────────────────────────┐                 │
│              │       3. 定位瓶颈并优化        │                 │
│              └────────────┬───────────────────┘                 │
│                           ↓                                     │
│              ┌────────────────────────────────┐                 │
│              │       4. 验证优化效果          │                 │
│              └────────────────────────────────┘                 │
└─────────────────────────────────────────────────────────────────┘

二、JVM GC 排查

2.1 常用命令

# 查看GC状态(每1秒输出一次)
jstat -gcutil <pid> 1000
 
# 查看堆内存使用
jmap -heap <pid>
 
# 生成堆转储文件
jmap -dump:format=b,file=heapdump.hprof <pid>
 
# 查看线程栈
jstack <pid> > thread_dump.txt
 
# 查看类加载统计
jstat -class <pid>

2.2 GC 日志分析

# JVM启动参数配置GC日志
java -XX:+PrintGCDetails \
     -XX:+PrintGCTimeStamps \
     -XX:+PrintGCApplicationStoppedTime \
     -Xloggc:gc.log \
     -jar application.jar

2.3 常见GC问题

问题类型现象原因解决方案
频繁Full GC老年代占用高大对象分配、内存泄漏分析堆转储,优化对象生命周期
GC停顿过长STW时间超过200ms堆内存过大、GC算法不当切换G1GC,调整堆大小
内存泄漏老年代持续增长对象引用未释放使用MAT分析引用链

2.4 工具推荐

工具用途
jstatJVM统计信息
VisualVM可视化监控
Arthas在线诊断
MAT堆转储分析

三、慢SQL 排查

3.1 开启慢查询日志

# MySQL配置
slow_query_log = ON
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2  # 超过2秒记录
log_queries_not_using_indexes = ON  # 记录未使用索引的查询

3.2 使用EXPLAIN分析

EXPLAIN SELECT * FROM orders 
WHERE store_id = 123 
  AND create_time > '2024-01-01';

3.3 EXPLAIN字段解读

字段说明
type访问类型(ALL、index、range、ref、eq_ref)
key使用的索引
rows扫描行数
Extra额外信息(Using index、Using where、Using filesort)

3.4 常见SQL优化

-- 优化前:全表扫描
SELECT * FROM orders WHERE status = 'PAID';
 
-- 优化后:使用索引
CREATE INDEX idx_orders_status ON orders(status);
 
-- 优化前:深分页问题
SELECT * FROM orders LIMIT 100000, 10;
 
-- 优化后:使用游标或覆盖索引
SELECT * FROM orders 
WHERE id > (SELECT id FROM orders LIMIT 100000, 1) 
LIMIT 10;

四、网络I/O 排查

4.1 常用命令

# 查看连接状态
netstat -anp | grep <port>
 
# 抓包分析
tcpdump -i eth0 port 8080 -w capture.pcap
 
# 网络延迟测试
ping <host>
mtr <host>
 
# 接口响应时间
curl -w "Time: %{time_total}s\n" http://localhost:8080/api/orders

4.2 连接池配置检查

@Configuration
public class DataSourceConfig {
    @Bean
    public DataSource dataSource() {
        HikariCPConfig config = new HikariCPConfig();
        config.setMaximumPoolSize(20);
        config.setMinimumIdle(5);
        config.setConnectionTimeout(30000);  // 30秒超时
        config.setIdleTimeout(600000);      // 10分钟空闲回收
        return new HikariDataSource(config);
    }
}

五、线程池阻塞排查

5.1 线程池监控

public class ThreadPoolMetrics {
    private final ThreadPoolExecutor executor;
    
    public ThreadPoolMetrics(ThreadPoolExecutor executor) {
        this.executor = executor;
    }
    
    public Map<String, Object> getMetrics() {
        return Map.of(
            "activeThreads", executor.getActiveCount(),
            "poolSize", executor.getPoolSize(),
            "queueSize", executor.getQueue().size(),
            "completedTasks", executor.getCompletedTaskCount(),
            "totalTasks", executor.getTaskCount()
        );
    }
}

5.2 常见问题

问题现象解决方案
队列积压queueSize持续增长增加线程数或优化任务处理时间
拒绝策略触发CallerRunsPolicy执行调整队列大小或拒绝策略
线程死锁activeThreads满但任务不完成检查线程栈分析死锁

六、全链路监控

6.1 分布式追踪

// 使用OpenTelemetry
@Autowired
private Tracer tracer;
 
public Order getOrder(Long orderId) {
    try (Span span = tracer.spanBuilder("getOrder").startSpan()) {
        span.setAttribute("orderId", orderId);
        // ...业务逻辑
    }
}

6.2 关键指标监控

指标说明告警阈值
P50/P95/P99响应时间分位值P95 > 500ms
错误率请求失败比例> 1%
QPS每秒请求数根据业务调整
线程池队列长度积压任务数> 1000

七、面试要点

7.1 核心概念

概念说明
GC停顿垃圾回收时应用暂停时间
慢查询执行时间超过阈值的SQL
连接池数据库连接复用机制
分布式追踪跨服务请求链路追踪

7.2 常见面试问题

Q:如何定位接口响应慢的问题?

A:从四个维度排查:JVM GC、慢SQL、网络I/O、线程池阻塞,使用jstat、EXPLAIN、netstat等工具。

Q:深分页问题如何解决?

A:使用游标、覆盖索引、或禁止深分页查询。

Q:线程池队列满了怎么办?

A:增加最大线程数、使用有界队列配合合理拒绝策略、优化任务处理速度。


参考链接