JDK 17 +spiring boot+ maven 应用服务 高并发调优

覆盖 JVM 调优、Spring Boot 调优、Tomcat 调优、数据库调优、Maven 构建优化

一、高并发调优核心目标

  1. 降低GC 停顿时间(目标 < 100ms)
  2. 提升QPS ,降低响应时间
  3. 避免线程阻塞 / 死锁 / 内存泄漏
  4. 充分利用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 TimeThroughput

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(并行执行)

核心价值

  1. 利用多核 CPU:将串行任务并行化,充分利用服务器 CPU 资源
  2. 减少请求阻塞:主线程快速响应,耗时操作丢给线程池异步执行
  3. 削峰填谷:通过队列缓冲突发请求,避免瞬间压垮数据库 / 下游服务

步骤 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 优化 并行构建编译

相关推荐
AMoon丶2 小时前
Golang--锁
linux·开发语言·数据结构·后端·算法·golang·mutex
白杆杆红伞伞2 小时前
Qt进程间通信
开发语言·qt
艾莉丝努力练剑2 小时前
确保多进程命名管道权限一致的方法
java·linux·运维·服务器·开发语言·网络·c++
tiany5242 小时前
养虾记录-如何配置多agent和多个飞书机器人独立对话
java·前端·飞书
旺仔流奶啊~2 小时前
idea使用Screw工具一键生成数据库文档详解
java·数据库·intellij-idea
2201_756206342 小时前
1111111
开发语言·python
一瓢西湖水2 小时前
CPU使用超过阈值分析
java·开发语言·jvm
特种加菲猫2 小时前
透过源码看本质:list 的模拟实现与核心原理
开发语言·c++
李日灐2 小时前
改造红黑树实现封装 map/set:感受C++ 标准容器的精妙设计与底层实现
开发语言·数据结构·c++·后端·算法·红黑树