一、概述
Spring Boot 接口慢的根因通常集中在 数据库、代码逻辑、并发处理 三个层面。以下是按优先级和场景整理的解决方案。
二、诊断先行:先定位瓶颈
优化前必须先找到真正的慢点,避免盲目优化:
| 工具/方法 | 用途 |
|---|---|
| Arthas | 实时查看方法耗时、trace 慢调用栈 |
| Spring Boot Actuator + Micrometer | 监控接口 RT、JVM 指标 |
| 慢 SQL 日志 | spring.datasource.druid.filter.stat.log-slow-sql=true |
| SkyWalking / Pinpoint | 分布式链路追踪,定位跨服务耗时 |
| jstack / jprofiler | 分析线程阻塞、死锁 |
三、数据库层优化(最常见)
1. SQL 与索引
-
加索引 :
EXPLAIN分析执行计划,对WHERE、ORDER BY、JOIN字段加索引 -
避免
SELECT *:只查必要字段,减少网络 IO 和内存占用 -
大表分页优化 :深分页
LIMIT 100000, 10改为 游标分页 (WHERE id > ? LIMIT 10)或 延迟关联 -
批量操作 :用
INSERT ... VALUES (),()或 JDBCbatch替代逐条插入
2. 连接池调优
spring:
datasource:
hikari:
maximum-pool-size: 20 # 根据 CPU 核数和 DB 承载调整
minimum-idle: 10
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
3. ORM 优化
-
MyBatis :用
<foreach>批量操作;@MapKey减少嵌套查询 -
JPA/Hibernate:
-
开启
spring.jpa.properties.hibernate.default_batch_fetch_size=50(解决 N+1) -
避免在循环内触发懒加载(Open Session in View 关闭:
spring.jpa.open-in-view=false)
-
四、缓存层优化
1. 本地缓存(Caffeine)
适合读多写少、数据量小、容忍秒级延迟的场景:
@Bean
public Cache<String, Object> caffeineCache() {
return Caffeine.newBuilder()
.maximumSize(10_000)
.expireAfterWrite(5, TimeUnit.MINUTES)
.build();
}
2. 分布式缓存(Redis)
-
缓存热点数据(如用户信息、配置字典)
-
接口级缓存:
@Cacheable(value = "user", key = "#id") -
防止缓存击穿:布隆过滤器或互斥锁
-
大对象压缩:缓存前用
Snappy/GZIP压缩 JSON
五、代码与业务逻辑优化
1. 异步化
-
接口内部异步 :用
@Async+CompletableFuture并行调用多个独立服务 -
接口异步返回 :
DeferredResult/WebFlux(适合长轮询或 SSE)@Async
public CompletableFuturegetUserAsync(Long id) { ... } // controller 中
CompletableFutureu = service.getUserAsync(id);
CompletableFutureo = service.getOrderAsync(id);
CompletableFuture.allOf(u, o).join();
2. 减少外部 HTTP 调用
-
合并多次 RPC/HTTP 请求为一次批量接口
-
外部调用加 熔断降级(Sentinel / Resilience4j),防止拖垮自身
-
配置合理的超时:
connectTimeout=3s,readTimeout=5s
3. 大对象与序列化
-
避免返回超大 List(> 1万条),改为分页 或流式导出
-
JSON 序列化器换为 Jackson Afterburner 或 protobuf,减少 CPU 消耗
-
开启 HTTP 压缩:
server.compression.enabled=true
六、JVM 与运行时优化
1. GC 调优
# G1 收集器(JDK 11+ 默认,适合大堆)
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:+UseStringDeduplication
# ZGC(JDK 17+,超低延迟)
-XX:+UseZGC
- 观察 GC 日志,如果 Full GC 频繁,检查是否有内存泄漏或大对象分配
2. 线程池调优
Tomcat 默认线程池可能不够用:
server:
tomcat:
threads:
max: 500 # 根据业务调整,不是越大越好
min-spare: 50
max-connections: 10000
accept-count: 1000 # 队列长度
七、架构与部署层
| 方案 | 适用场景 |
|---|---|
| CDN / Nginx 缓存 | 静态资源、不常变的接口响应 |
| 读写分离 | 读请求远大于写,MySQL 主从架构 |
| 分库分表 | 单表数据量 > 千万级 |
| 接口限流 | 防止突发流量把 DB 打挂(Sentinel 限流) |
| Nginx 负载均衡 | 多实例横向扩展。水平扩容:实例加多,配合负载均衡。 |
| 接口拆分 | 大接口拆小接口,按需获取,不要一次性返回全部数据。 |
| 预计算 | 报表、统计类不要实时计算;定时任务预计算结果存入缓存,接口直接读预计算结果。 |
| 分页 | 列表接口强制分页,禁止全量返回。 |
八、快速检查清单
- 该接口是否有慢 SQL?(> 100ms 就要警惕)
- 是否触发了 N+1 查询?
- 是否能加缓存?数据更新是否频繁?
- 是否有循环内部调用外部 HTTP/RPC?
- 返回数据量是否过大?是否可分页?
- JVM 是否有 Full GC 停顿?
- 线程池是否被打满?(Tomcat 线程全部阻塞)
九、建议的优化顺序
慢 SQL / 索引 → 加缓存 → 异步化 → JVM 调优 → 架构升级。