java-SpringBoot-线程池配置-压力测试(理论版)
线程池描述当代码中需要创建线程时使用(如:异步订单处理,批量数据处理,数据导出导入类等不需要实时返回的情况)原理配置线程池使用线程池工具创建线程(new Thread() 不算)当执行创建第一个线程代码时,开始创建第一次核心线程每次创建线程,判断是否超线程池配置的最小值,如果未超正常创建核心线程超了线程池配置的最小值,进队列队列也满了,判断是否达到线程池配置的最大值,如果未超,创建非核心线程超了线程池配置的最大值,后续超出的线程根据配置的拒绝策略执行线程池配置线程池配置来源:可以根据压力测试得到的结果来做配置主要参数线程池最小值描述:每次创建线程,判断是否超线程池配置的最小值,如果未超正常创建核心线程线程池最大值描述:当前线程达到线程池配置的最小值,并且队列也满了,判断是否达到线程池配置的最大值,如果未超,创建非核心线程队列最大长度描述:每次创建线程,判断是否超线程池配置的最小值,如果未超正常创建核心线程,超了线程池配置的最小值,进队列,当前线程达到线程池配置的最小值,并且队列也满了,判断是否达到线程池配置的最大值,如果未超,创建非核心线程线程池前缀描述:用于日志区分对应线程//创建线程池对象 ThreadPoolTaskExecutor executor new ThreadPoolTaskExecutor(); //配置线程池最小数量 executor.setCorePoolSize(10); //配置线程池最大数量 executor.setMaxPoolSize(200); //配置队列最大长度 executor.setQueueCapacity(10); //配置线程池前缀 executor.setThreadNamePrefix(executor-);线程池拒绝策略描述:当队列满了,并且线程达到线程池配置的最大值,后续超出的线程根据配置的拒绝策略执行配置线程池代码ps:拿已上线springBoot工程配置代码import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.task.TaskExecutor; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.ThreadPoolExecutor; Configuration EnableAsync(proxyTargetClass true) public class AsycTaskConfig { /** * 线程池维护线程的最小数量. */ Value(${asyc-task.corePoolSize:10}) private int corePoolSize; /** * 线程池维护线程的最大数量 */ Value(${asyc-task.maxPoolSize:200}) private int maxPoolSize; /** * 队列最大长度 */ Value(${asyc-task.queueCapacity:10}) private int queueCapacity; /** * 线程池前缀 */ Value(${asyc-task.threadNamePrefix:executor-}) private String threadNamePrefix; Bean public TaskExecutor taskExecutor() { ThreadPoolTaskExecutor executor new ThreadPoolTaskExecutor(); executor.setCorePoolSize(corePoolSize);//最小线程池数量 executor.setMaxPoolSize(maxPoolSize);//最大线程池数量 executor.setQueueCapacity(queueCapacity);//队列最大长度 //这个项目的线程池前缀,方便看日志区分是哪个线程 executor.setThreadNamePrefix(threadNamePrefix); /* * 线程池拒绝策略:当线程池内数量达到 maxPoolSize 且工作队列已满时, * 才会触发拒绝策略,根据配置的拒绝策略处理当前已超出的线程,默认抛异常 */ /* * AbortPolicy默认策略 * 行为直接抛出 RejectedExecutionException 异常 * 适用场景必须保证任务不能丢失需要上层捕获异常处理 */ // executor.setRejectedExecutionHandler( // new ThreadPoolExecutor.AbortPolicy()); /* * CallerRunsPolicy调用者运行策略 * 行为不在新线程中执行而是由提交任务的线程调用者自己执行 * 适用场景降低新任务提交速度起到反压作用避免任务丢失 */ executor.setRejectedExecutionHandler( new ThreadPoolExecutor.CallerRunsPolicy()); /* * DiscardPolicy丢弃策略 * 行为直接丢弃新提交的任务不抛出异常 * 适用场景允许任务丢失对结果不敏感的场景 */ // executor.setRejectedExecutionHandler( // new ThreadPoolExecutor.DiscardPolicy()); /* * DiscardOldestPolicy丢弃最旧策略 * 行为丢弃队列中最老的任务最早进入队列的然后重新尝试提交新任务 * 适用场景优先处理新任务允许旧任务过期 */ // executor.setRejectedExecutionHandler( // new ThreadPoolExecutor.DiscardOldestPolicy()); //配置完成,初始化 executor.initialize(); return executor; } }创建线程代码taskExecutor.execute(() - { //线程池执行代码 //发送短信,邮件 //异步修改订单状态等 });压力测试-获取线程池配置ps:纯理论,从AI那得到的信息描述最好在生产环境下压测根据调整并发数看压测结果,来调整线程池配置下载压测工具打开 Apache JMeter 的官方下载页面https://jmeter.apache.org/download_jmeter.cgi点击 apache-jmeter-5.6.3.zip apache-jmeter-x.x.x.zip,下载压缩包 如:apache-jmeter-5.6.3.zip解压后双击bin/jmeter.bat即可运行压测工具配置改成中文测试计划配置定义测试计划名称在左侧的“测试计划”上点击鼠标右键,选择添加-线程用户-线程组线程组配置线程数:并发用户数同时执行请求的线程数量Ramp-Up时间:启动所有线程所需的时间,例如线程数10Ramp-Up5秒→ 每秒启动2个线程循环次数:每个线程执行请求的次数,总请求数 线程数 × 循环次数调度器:不勾选调度器:线程启动后执行完循环次数就结束,总请求数 线程数 × 循环次数固定勾选调度器:循环次数此时会失效或建议设为“永远”;线程会在持续时间内反复执行;启动延迟是指调度器延迟多久开始执行只延迟一次下图配置:1秒内启动1000个线程,在线程全部启动后,120秒内线程会重复执行,总时长 1(Ramp-Up时间) 120(持续时间) 121秒每次修改线程组需要保存,最好清除一下聚合报告再启动单接口配置目标请求配置在刚建好的“线程组”上点击鼠标右键。选择添加-取样器-HTTP请求请求名称:自定义协议:http 或 https服务器名称或ip:自己根据服务器配置,本地的话配 localhost端口号:自己根据代码配置HTTP请求:自己根据接口配置路径:自己根据接口配置下图配置: GET http://localhost:8080/hello监听器配置还是在“线程组”上点击鼠标右键。选择添加-监听器-聚合报告。也可以多加个查看结果树,它能显示每个请求的详细请求数据和返回结果方便你第一时间确认脚本配置是否正确,压测的时候禁用查看结果树(右键 - 禁用),会消耗大量本地的CPU和内存资源导致测试结果不准确聚合报告:分析时用。压测结束后这个报告会汇总关键数据比如平均响应时间、吞吐量TPS、错误率等。这些就是你调整线程池配置的重要依据多接口配置吞吐量控制器右键线程组 →添加→逻辑控制器→吞吐量控制器下图配置,按百分比分配请求,并且占比50%,如果多个吞吐量控制器总数不是100%,会按比例分配目标请求配置在刚建好的多个“吞吐量控制器”上点击鼠标右键。选择添加-取样器-HTTP请求,分别配置多个接口,其他跟上面跟单接口配置一样一样配置监听器配置在线程组新建,跟上面跟单接口配置一样一样配置查看聚合报告聚合报告指标描述数值样本数本次压测中总共发送的请求数量总请求数1,922,779平均值所有请求的平均耗时62 ms中位数50%的请求 ≤ 这个值64 ms90%分位90%的请求在 X ms 内完成85 ms95%分位95%的请求在 X ms 内完成92 ms99%分位99%的请求在 X ms 内完成118 ms最小值最快响应时间0ms最大值最慢响应时间1298 ms异常率失败请求占比0.07%吞吐量每秒处理的请求数(QPS)16,030 /秒压测数据导出如果有压测目标,则直接按目标配置线程组数量,如果没有,则慢慢增加压测线程数直到吞吐量最大值,得出最大值后,优化代码,线程池,数据库,缓存,架构等优化每个压测数量最好跑3次,取平均值ps:可以把数据发给AI 让AI帮忙整理分析,给建议修改代码线程池配置根据项目类型初步配置代码线程池参数初步线程池配置任务类型特点线程池max 建议线程数原因CPU 密集型大量计算CPU一直忙CPU 核心数 1避免上下文切换IO 密集型等待数据库/网络/磁盘CPU 核心数 × (1 IO等待时间/CPU时间)让 CPU 不空闲混合型两者都有根据压测调整找拐点根据吞吐量,请求耗时,调整线程池最大值以及队列长度生产环境线程池配置AI答复:生产环境在压测最优值10/50/100基础上放大 20-50%推荐 core20, max100, queue300既能应对突发又不浪费资源压测完成后根据数据检查这5个问题1. 异常率是否 1% → 是修错误 | 否继续2. 99%分位是否超过预期 → 是优化响应 | 否继续3. 吞吐量是否达到目标 → 是达标 | 否扩容/优化4. 资源利用率是否合理 → CPU/内存/连接池是否打满5. 波动是否过大 → 中位数与平均值是否接近