覆盖 JVM 调优、Spring Boot 调优、Tomcat 调优、数据库调优、Maven 构建优化
一、高并发调优核心目标
- 降低GC 停顿时间(目标 < 100ms)
- 提升QPS ,降低响应时间
- 避免线程阻塞 / 死锁 / 内存泄漏
- 充分利用CPU / 内存 / 网络资源
二、分模块调优(按优先级排序)
1. JVM 调优(JDK 17 专属)
JDK 17 默认用 G1GC ,但高并发场景建议用 ZGC(低延迟、大内存友好)。
1.1 ZGC 调优(推荐,JDK 17 正式支持)
# JVM 参数(放到启动脚本/IDE VM options)
-Xms8g -Xmx8g # 堆内存固定(避免动态调整)
-XX:+UseZGC # 启用ZGC
-XX:ZCollectionInterval=10 # 每10秒触发一次GC(按需调整)
-XX:+UnlockExperimentalVMOptions
-XX:+ZGenerational # JDK 17+ 开启分代ZGC(更高效)
-XX:+DisableExplicitGC # 禁止System.gc()
-XX:+HeapDumpOnOutOfMemoryError # OOM时导出堆快照
-XX:HeapDumpPath=/tmp/heapdump.hprof
-Xlog:gc*:file=/tmp/gc.log:time,level,tags # GC日志
-XX:NativeMemoryTracking=summary # 本地内存跟踪(排查内存泄漏)
1.2 G1GC 调优(兼容场景)
如果暂不升级 ZGC,G1GC 调优:
-Xms8g -Xmx8g
-XX:+UseG1GC
-XX:G1HeapRegionSize=32M # 区域大小(根据堆内存调整)
-XX:MaxGCPauseMillis=100 # 目标停顿时间
-XX:G1NewSizePercent=20 # 新生代最小占比
-XX:G1MaxNewSizePercent=50 # 新生代最大占比
-XX:+ParallelRefProcEnabled # 并行处理引用
1.3 关键说明
- 堆内存 :生产环境建议固定
-Xms=-Xmx(避免内存抖动),大小为物理内存的 50%-70%。 - ZGC 优势:停顿时间 < 10ms,支持 TB 级堆内存,适合高并发、低延迟场景。
- GC 日志分析 :用
GCViewer工具,重点看Pause Time和Throughput。
2. Spring Boot 调优
2.1 核心线程池调优(异步 / 请求处理)
步骤 1:优化线程池配置(适配高并发)
java
@Configuration
@EnableAsync // 开启Spring异步支持
public class ThreadPoolConfig {
// 核心业务线程池(CPU密集型)
@Bean("bizExecutor")
public Executor bizExecutor() {
// CPU密集型:核心线程数 = CPU核心数 * 2
// IO密集型:核心线程数 = CPU核心数 * 4(如DB/网络请求多)
int core = Runtime.getRuntime().availableProcessors() * 2;
int max = core * 4;
ThreadPoolExecutor executor = new ThreadPoolExecutor(
core,
max,
60L,
TimeUnit.SECONDS,
// 用ArrayBlockingQueue(有界),避免OOM;容量按QPS调整
new ArrayBlockingQueue<>(2000),
// 自定义线程工厂(带前缀,方便排查问题)
new ThreadFactory() {
private final AtomicInteger count = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r, "biz-thread-" + count.getAndIncrement());
thread.setDaemon(true); // 守护线程,JVM退出时自动销毁
return thread;
}
},
// 拒绝策略:高并发时先记录日志,再降级处理
new ThreadPoolExecutor.CallerRunsPolicy() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
// 记录拒绝日志(关键:方便排查高并发问题)
log.warn("线程池已满,任务被拒绝!核心线程数:{},最大线程数:{},队列大小:{}",
e.getCorePoolSize(), e.getMaximumPoolSize(), e.getQueue().size());
// 调用者运行(兜底:主线程执行,避免任务丢失)
super.rejectedExecution(r, e);
}
}
);
// 核心:允许核心线程超时回收(减少空闲资源占用)
executor.allowCoreThreadTimeOut(true);
return executor;
}
// IO密集型线程池(如DB查询、HTTP调用)
@Bean("ioExecutor")
public Executor ioExecutor() {
int core = Runtime.getRuntime().availableProcessors() * 4;
int max = core * 2;
// IO密集型用更大的队列
return new ThreadPoolExecutor(
core, max, 60L, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(5000),
new ThreadFactory() {
private final AtomicInteger count = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "io-thread-" + count.getAndIncrement());
}
},
new ThreadPoolExecutor.CallerRunsPolicy()
);
}
}
为什么异步线程池能提升性能?
同步执行的问题:
请求 → 接口A(耗时200ms)→ 接口B(耗时300ms)→ 接口C(耗时100ms)→ 返回
总耗时 = 200+300+100 = 600ms(串行阻塞)
异步线程池的优势:前提是接口A、B、C之前无依赖关系
请求 → 主线程接收请求
├─ 线程池1执行接口A(200ms)
├─ 线程池2执行接口B(300ms)
└─ 线程池3执行接口C(100ms)
总耗时 = max(200,300,100) = 300ms(并行执行)
核心价值:
- 利用多核 CPU:将串行任务并行化,充分利用服务器 CPU 资源
- 减少请求阻塞:主线程快速响应,耗时操作丢给线程池异步执行
- 削峰填谷:通过队列缓冲突发请求,避免瞬间压垮数据库 / 下游服务
步骤 2:异步化耗时操作(核心落地)
场景 1:接口内异步执行非核心逻辑(如日志、通知、统计)
java
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private OrderService orderService;
// 同步接口:下单(核心逻辑)+ 发短信(非核心)
@PostMapping("/create")
public Result createOrder(@RequestBody OrderDTO dto) {
// 1. 同步执行核心逻辑(必须立即完成)
OrderVO order = orderService.createOrder(dto);
// 2. 异步执行非核心逻辑(耗时但不影响主流程)
CompletableFuture.runAsync(() -> {
orderService.sendSms(order.getPhone()); // 发短信
orderService.recordLog(order.getId()); // 记录操作日志
orderService.updateStatistics(); // 更新统计数据
}, (Executor) ApplicationContextUtil.getBean("bizExecutor"));
// 主线程快速返回,提升接口响应速度
return Result.success(order);
}
}
场景 2:并行执行多个耗时操作(如多接口聚合)
java
@Service
public class OrderService {
@Autowired
private UserService userService;
@Autowired
private InventoryService inventoryService;
@Autowired
private PayService payService;
// 异步并行查询,提升聚合接口性能
public OrderDetailVO getOrderDetail(Long orderId) {
// 1. 异步查询用户信息
CompletableFuture<UserVO> userFuture = CompletableFuture.supplyAsync(() -> {
return userService.getUserById(orderId);
}, (Executor) ApplicationContextUtil.getBean("ioExecutor"));
// 2. 异步查询库存信息
CompletableFuture<InventoryVO> inventoryFuture = CompletableFuture.supplyAsync(() -> {
return inventoryService.getInventoryByOrderId(orderId);
}, (Executor) ApplicationContextUtil.getBean("ioExecutor"));
// 3. 异步查询支付信息
CompletableFuture<PayVO> payFuture = CompletableFuture.supplyAsync(() -> {
return payService.getPayInfoByOrderId(orderId);
}, (Executor) ApplicationContextUtil.getBean("ioExecutor"));
// 4. 等待所有异步任务完成(并行执行,总耗时=最长的那个任务)
CompletableFuture.allOf(userFuture, inventoryFuture, payFuture).join();
// 5. 组装结果
OrderDetailVO detail = new OrderDetailVO();
detail.setUser(userFuture.join());
detail.setInventory(inventoryFuture.join());
detail.setPay(payFuture.join());
return detail;
}
}
场景 3:Spring @Async 注解(简化异步调用)
java
@Service
public class AsyncTaskService {
// 指定使用bizExecutor线程池
@Async("bizExecutor")
public CompletableFuture<Boolean> sendSms(String phone, String content) {
try {
// 模拟发短信耗时
Thread.sleep(500);
log.info("发送短信:{},内容:{}", phone, content);
return CompletableFuture.completedFuture(true);
} catch (Exception e) {
log.error("发短信失败", e);
return CompletableFuture.completedFuture(false);
}
}
@Async("ioExecutor")
public CompletableFuture<Boolean> updateInventory(Long productId, Integer num) {
// 模拟DB操作耗时
Thread.sleep(300);
log.info("扣减库存:{},数量:{}", productId, num);
return CompletableFuture.completedFuture(true);
}
}
步骤 3:线程池监控(避免性能瓶颈)
添加线程池监控,实时掌握运行状态:
java
@Component
public class ThreadPoolMonitor {
@Autowired
@Qualifier("bizExecutor")
private Executor bizExecutor;
@Autowired
@Qualifier("ioExecutor")
private Executor ioExecutor;
// 每10秒打印一次线程池状态
@Scheduled(fixedRate = 10000)
public void monitorThreadPool() {
monitor("核心业务线程池", (ThreadPoolExecutor) bizExecutor);
monitor("IO密集型线程池", (ThreadPoolExecutor) ioExecutor);
}
private void monitor(String name, ThreadPoolExecutor executor) {
log.info("【{}】状态:核心线程数={}, 活跃线程数={}, 最大线程数={}, 完成任务数={}, 队列大小={}, 队列剩余容量={}",
name,
executor.getCorePoolSize(),
executor.getActiveCount(),
executor.getMaximumPoolSize(),
executor.getCompletedTaskCount(),
executor.getQueue().size(),
executor.getQueue().remainingCapacity());
}
}
线程池参数选型(核心)
| 任务类型 | 核心线程数 | 最大线程数 | 队列类型 | 队列大小 |
|---|---|---|---|---|
| CPU 密集型(计算) | CPU 核心数 * 2 | 核心数 * 4 | ArrayBlockingQueue | 1000-2000 |
| IO 密集型(DB / 网络) | CPU 核心数 * 4 | 核心数 * 8 | ArrayBlockingQueue | 3000-5000 |
避免常见坑
- ❌ 不要用
newCachedThreadPool(无界线程池,高并发会创建大量线程导致 OOM) - ❌ 不要用
LinkedBlockingQueue(无界队列,高并发会堆积任务导致 OOM) - ❌ 不要忽略拒绝策略(高并发时任务丢失,必须记录日志 + 兜底)
- ❌ 不要异步执行核心逻辑(如订单创建、支付,异步会导致结果返回不及时)
2.2 关闭无用自动配置
java
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class, // 不用JDBC则排除
RedisAutoConfiguration.class, // 不用Redis则排除
RabbitAutoConfiguration.class, // 不用MQ则排除
WebMvcAutoConfiguration.class // 自定义Web配置时排除
})
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
2.3 配置文件调优(application.yml)
spring:
# 1. 关闭JMX(生产无用,节省资源)
jmx:
enabled: false
# 2. 异步配置
task:
execution:
pool:
core-size: 8
max-size: 32
queue-capacity: 1000
keep-alive: 60s
# 3. 缓存配置(减少重复计算)
cache:
type: caffeine
caffeine:
spec: maximumSize=10000,expireAfterWrite=5m
# 4. 日志调优(异步日志,减少IO阻塞)
logging:
pattern:
console: "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
file:
name: /tmp/app.log
logback:
rollingpolicy:
max-file-size: 100MB
max-history: 7
level:
root: INFO
org.springframework: WARN
com.zaxxer.hikari: WARN
3. Web 容器调优(Tomcat)
Spring Boot 默认用 Tomcat,调优连接数 / 线程数:
4. 数据库连接池调优(HikariCP)
Spring Boot 默认用 HikariCP(性能最优),调优连接数:
5. Maven 构建优化(提升打包速度)
5.1 pom.xml 优化 并行构建编译