【线程池】压测确定线程池合适的参数

  • 【一】案例说明
  • 【二】明确线程池核心参数及优化目标
    • 【1】线程池核心参数(需压测验证的关键参数)
    • 【2】优化目标
  • 【三】压测前准备
    • 【1】环境搭建
    • 【2】线程池初始配置(基于经验值)
    • 【3】压测工具与监控指标
  • 【四】压测方案设计(控制变量法)
    • 【1】场景 1:确定最佳核心线程数(corePoolSize)
    • 【2】场景 2:确定最大线程数(maximumPoolSize)
    • 【3】场景 3:确定任务队列大小(queueCapacity)
    • 【4】场景 4:验证拒绝策略(rejectedExecutionHandler)
  • 【五】压测结果分析与最优配置确定
    • 【1】关键指标对比表(示例)
    • 【2】最优配置判断标准
  • 【六】最终验证与动态调整
  • 【七】总结

【一】案例说明

现在有一个springboot项目,有一个接口是使用easyexcel对100万条数据进行批量导出,引入线程池提高效率,通过压测来得到线程池合适的配置参数

【二】明确线程池核心参数及优化目标

【1】线程池核心参数(需压测验证的关键参数)

(1)corePoolSize:核心线程数(始终存活的线程数)。
(2)maximumPoolSize:最大线程数(核心线程忙时可扩容的最大线程数)。
(3)workQueue:任务队列(核心线程忙时,新任务的缓冲队列,如LinkedBlockingQueue)。
(4)keepAliveTime:非核心线程空闲存活时间(超出核心线程数的线程,空闲后销毁的时间)。
(5)rejectedExecutionHandler:拒绝策略(任务队列满且线程数达最大值时的处理策略,如AbortPolicy/CallerRunsPolicy)。

【2】优化目标

(1)吞吐量:单位时间内成功导出的任务数(越高越好)。
(2)响应时间:单个导出任务的平均 / 90%/99% 响应时间(越低越好)。
(3)资源利用率:CPU 使用率(建议≤80%)、内存使用率(无 OOM 风险)、线程池活跃线程数(无大量空闲线程)。
(4)稳定性:无任务被拒绝、无数据库连接池耗尽、无频繁 GC。

【三】压测前准备

【1】环境搭建

(1)硬件:测试环境配置需接近生产(如 CPU 核心数、内存大小、磁盘 IO),避免因环境差异导致结果失真。
(2)依赖隔离:压测期间关闭其他非必要服务(如定时任务、其他接口),确保资源仅用于导出接口。
(3)数据准备:提前在测试库中准备 100 万条符合生产特征的测试数据(避免压测时因数据生成消耗资源)。

【2】线程池初始配置(基于经验值)

导出任务属于IO 密集型(涉及数据库查询 IO、文件写入 IO),初始参数可参考经验值:

@Configuration
public class ThreadPoolConfig {@Bean("exportExecutor")public Executor exportExecutor() {// 获取CPU核心数(假设测试机为8核)int cpuCore = Runtime.getRuntime().availableProcessors();ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(cpuCore * 2); // 核心线程数:IO密集型通常为CPU核心数*2executor.setMaxPoolSize(cpuCore * 4);  // 最大线程数:核心线程数的2倍executor.setQueueCapacity(1000);       // 任务队列大小:初始1000executor.setKeepAliveSeconds(60);      // 非核心线程空闲60秒销毁executor.setThreadNamePrefix("export-");// 拒绝策略:任务队列满时,让提交任务的线程执行(避免任务丢失,同时限流)executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());executor.initialize();return executor;}
}

【3】压测工具与监控指标

压测工具:JMeter(简单易用)或 Gatling(高并发场景更稳定)。

监控指标:
(1)系统层面:CPU 使用率、内存使用率、磁盘 IO(导出文件写入速度)、网络 IO(若涉及远程存储)。
(2)JVM 层面:堆内存使用、GC 次数 / 耗时(避免频繁 Full GC)、线程数(活跃线程 / 阻塞线程)。
(3)应用层面:接口响应时间(平均 / 90%/99%)、吞吐量(TPS)、线程池状态(活跃线程数、队列等待数、拒绝任务数)。
(4)数据库层面:连接池使用率、查询响应时间、锁等待(避免导出时数据库成为瓶颈)。

【四】压测方案设计(控制变量法)

每次仅调整 1 个参数,其他参数固定,对比不同配置下的指标变化。

【1】场景 1:确定最佳核心线程数(corePoolSize)

(1)固定参数:maxPoolSize = 32(8 核 CPU×4)、queueCapacity = 1000、keepAliveTime = 60s。
(2)变量:corePoolSize 取值:4、8、16、24、32(基于 CPU 核心数的 0.5~4 倍)。
(3)压测条件:并发用户数 = 50(模拟实际可能的最大并发导出请求),持续压测 10 分钟。
(4)观察指标:
当corePoolSize过小时(如 4):活跃线程数很快达上限,任务大量进入队列,响应时间变长。
当corePoolSize过大时(如 32):CPU 使用率可能超过 80%,上下文切换频繁,吞吐量下降。
最佳值:CPU 使用率稳定在 60%~70%,响应时间最短,吞吐量最高的corePoolSize。

【2】场景 2:确定最大线程数(maximumPoolSize)

(1)固定参数:corePoolSize = 场景1的最佳值、queueCapacity = 1000、keepAliveTime = 60s。
(2)变量:maximumPoolSize 取值:corePoolSize、corePoolSize×1.5、corePoolSize×2、corePoolSize×3。
(3)压测条件:并发用户数 = 100(高于日常并发,模拟峰值),持续压测 10 分钟。
(4)观察指标:
若maximumPoolSize= 核心线程数:高并发时任务全靠队列缓冲,响应时间可能过长。
若maximumPoolSize过大(如核心线程数 ×3):非核心线程频繁创建销毁,增加开销。
最佳值:非核心线程被触发(即活跃线程数 > corePoolSize),但未导致 CPU 过高(<80%),且响应时间无明显增加的配置。

【3】场景 3:确定任务队列大小(queueCapacity)

(1)固定参数:corePoolSize和maximumPoolSize为前两步最佳值,keepAliveTime = 60s。
(2)变量:queueCapacity 取值:500、1000、2000、5000(或使用无界队列Integer.MAX_VALUE)。
(3)压测条件:并发用户数 = 150(超峰值,测试队列缓冲能力),持续压测 10 分钟。
(4)观察指标:
队列过小(500):可能触发拒绝策略(任务被拒绝),但内存占用低。
队列过大(5000):任务堆积过多,内存占用飙升(尤其 100 万条数据的任务对象),可能 OOM。
最佳值:无任务被拒绝,且内存使用率稳定(堆内存占用 < 70%)的最小队列大小。

【4】场景 4:验证拒绝策略(rejectedExecutionHandler)

(1)固定参数:前 3 步的最佳corePoolSize、maximumPoolSize、queueCapacity。
(2)变量:拒绝策略(AbortPolicy终止任务并抛异常、CallerRunsPolicy让提交线程执行、DiscardOldestPolicy丢弃最老任务)。
(3)压测条件:并发用户数 = 200(远超系统承载能力),持续 5 分钟。
(4)观察指标:
AbortPolicy:适合严格不允许任务丢失的场景,但会抛异常需业务处理。
CallerRunsPolicy:适合需要限流的场景(提交线程被阻塞,间接降低并发),但响应时间变长。
最佳策略:根据业务是否允许任务丢失选择,建议优先CallerRunsPolicy(避免任务丢失且自带限流)。

【五】压测结果分析与最优配置确定

【1】关键指标对比表(示例)

配置项吞吐量(TPS)平均响应时间(s)90% 响应时间(s)CPU 使用率内存使用率拒绝任务数
corePoolSize=8128.512.365%50%0
corePoolSize=16185.27.870%55%0
corePoolSize=24175.58.185%60%0

(表格解读:corePoolSize=16时,吞吐量最高,响应时间最短,CPU 使用率适中,为最佳值)

【2】最优配置判断标准

(1)吞吐量:在相同并发下,该配置的 TPS 最高。
(2)响应时间:90% 响应时间≤业务可接受阈值(如 10 秒)。
(3)资源稳定:CPU 使用率≤80%,内存无明显泄漏,GC 正常(无频繁 Full GC)。
(4)无任务丢失:拒绝任务数为 0(或在业务允许范围内)。

【六】最终验证与动态调整

稳定性验证:用最优配置,以日常并发的 1.5 倍持续压测 30 分钟,观察指标是否稳定(无明显波动)。
动态参数优化:生产环境可通过 Spring Cloud Config/Apollo 动态调整线程池参数(无需重启服务),例如:

// 动态修改核心线程数
@Autowired
private ThreadPoolTaskExecutor exportExecutor;public void updateCorePoolSize(int coreSize) {exportExecutor.setCorePoolSize(coreSize);
}

结合业务峰值:在已知业务峰值时段(如每日凌晨报表导出),临时调大corePoolSize和maximumPoolSize,峰值后恢复默认值。

【七】总结

通过 “控制变量法” 压测,重点关注核心线程数、最大线程数、队列大小三个参数,结合 IO 密集型任务特性(线程数可略高于 CPU 核心数),最终找到 “吞吐量高、响应时间短、资源占用合理” 的配置。对于 100 万条数据导出场景,典型最优配置可能为:corePoolSize=CPU核心数×2、maximumPoolSize=CPU核心数×3、queueCapacity=1000~2000,具体需根据实际压测结果调整。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/92447.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/92447.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/92447.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GPT OSS 双模型上线,百度百舸全面支持快速部署

GPT OSS 是 OpenAI 推出的重量级开放模型&#xff0c;专为强推理能力、智能体任务及多样化开发场景设计&#xff0c;标志着大模型在开放性与实用性上的重要突破。该系列包含两款高性能模型&#xff1a;参数规模为 117B 的 GPT‑OSS‑120B 和 21B 的 GPT‑OSS‑20B。二者皆采用 …

C++高频知识点(十七)

文章目录81. 你对智能指针的了解82. 一元、二元仿函数的区别和使用背景一元仿函数二元仿函数83. 描述Linux下文件删除的原理84. 什么是菱形继承&#xff1f;有什么问题&#xff0c;怎么解决&#xff1f;解决菱形继承问题85. IO多路复用是什么&#xff1f;selectpollepollselect…

如何优雅的使用进行参数校验

在spring里面有一个注解 Validated可以在方法的入参里面这样写//方法 getActivityFlag(RequestBody Validated QueryActivityDto queryActivityDto) //参数详情NotBlank(message "userId不能为空")private String userId;NotNull(message "storeId不能为空&q…

Java学习第一百一十部分——CI/CD

目录 一、前言简介 二、基本信息 三、优势价值 四、核心流程 五、技术栈&#xff08;工具矩阵&#xff09; 六、最佳实践 七、与DevOps关系 八、挑战对策 九、使用建议 十、总结归纳 一、前言简介 CI/CD 的本质是&#xff1a;通过自动化流水线&#xff0c;实现代码从提…

关于 Cocoapods 使用

一、Podfile & .podspec 文件 1、Podfile 1.1. 什么是 pod 简单来说&#xff0c;一个 pod 就是 xcode 里面的一个 dependency&#xff1a; Anyway&#xff0c;pod 就是第三方库的意思。一个 pod 就是指一个第三方库。 1.2. Podfile 有什么用 Podfile 可以理解为就是…

编程速递:2025 年巴西 Embarcadero 会议,期待您的到来

每个英雄都有一段充满奋斗的旅程&#xff0c;这段旅程引领他走向荣耀&#xff0c;而开发者英雄的旅程是2025年巴西Embarcadero大会的重点&#xff0c;以庆祝Delphi成立30周年。网站现已上线巴西Embarcadero在世界上最受期待的Delphi发展英雄会议召开前90天&#xff0c;推出了Em…

DevOps简单教程应用

文章目录概念一、环境准备二、gitlab配置三、.gitlab-ci.yml文件配置概念 Devops是一个概念&#xff0c;就是边开发边测试&#xff0c;能够大大提升开发效率&#xff0c;本文使用pycharmgitlab实现一个简单的DevOps流程 一、环境准备 需要一个测试环境&#xff0c;模拟部署&…

华为流程管理体系构建与落地 之—— 业务流程规划【附全文阅读】

这部分内容聚焦华为业务流程管理&#xff0c;详细阐述了流程规划、设计、运营、评估与优化的具体方法和内容&#xff0c;为企业构建和完善流程管理体系提供了全面的指导。流程规划分类方法&#xff1a;介绍 POS、OES、OMS 等分类法&#xff0c;如 POS 法按规划、运营、支持划分…

Android 项目:画图白板APP开发(零)——功能介绍(笔锋,分页,缩放,多指,硬件加速等)

一、前言 本系列将全面的介绍一些有关Android 画图方面的知识。笔触功能包括&#xff1a;颜色、粗细、透明度、笔锋、橡皮&#xff1b;绘图功能包括&#xff1a;分页、缩放、多指、撤销恢复、笔画加速。别看功能这么多&#xff0c;简单的部分会花较少篇幅介绍&#xff0c;着重会…

香橙派 RK3588 部署千问大模型 Qwen2-VL-2B 推理视频

演示视频 香橙派RK3588部署千问大模型Qwen2-VL-2B推理视频一、场景假设 视频输入为一条网络流&#xff0c;利用大模型对视频中的图像帧进行推理。由于大模型推理耗时长&#xff0c;无法对每帧都进行推理&#xff0c;因此采用跳帧推理的方式&#xff1a;当推理完一帧后&#xf…

排序概念以及插入排序

一、排序基本概念1.就地排序&#xff1a;使用恒定的额外空间来产生输出就地排序只是在原数组空间进行排序处理&#xff0c;也就是输入的数组和得到的数组是同一个2.内部排序和外部排序&#xff1a;待排序数据可以一次性载入到内存中为内部排序&#xff0c;反之数据量过大就是外…

Webpack 核心配置与最佳实践指南

Webpack 是现代前端工程化的核心工具,理解其配置原理和优化技巧对开发效率至关重要。 一、Webpack 基础架构 1、核心概念关系图 2、核心概念详解 概念 作用 示例配置 Entry 应用入口起点 entry: ‘./src/index.js’ Output 编译结果输出位置 output.path: path.resolve(__d…

GISBox私有云+SaaS:安全协同的地理智能平台

一、概述 GISBox&#xff08;GIS 工具箱&#xff09;是一套能够对GIS 影像、地形、倾斜摄影进行场景编辑、切片转化、分发服务的 GIS 工具箱。同时&#xff0c;GISBox还支持私有云并一键开启SaaS服务。 二、什么是私有云&#xff1f; 私有云服务是一种为企业或组织量身定制的…

代理人工智能的隐藏威胁

代理型人工智能的自主性令人兴奋&#xff0c;但事实并非如此。主动性越高&#xff0c;不可预测性就越强&#xff0c;这为严重的、往往被忽视的安全风险打开了大门。从指令劫持到数字供应链的连锁故障&#xff0c;代理型人工智能不仅智能&#xff0c;而且在不受控制的情况下非常…

SonarQube 扫描多个微服务模块

SonarQube 扫描多个微服务模块 在使用 SonarQube/SonarCloud 扫描多个微服务模块时&#xff0c;核心目标是​​确保每个微服务模块被独立分析​​&#xff0c;并在 SonarQube 界面中以独立项目展示结果。以下是具体实现方案&#xff0c;分场景说明&#xff1a; ​​一、前提条…

当前主流且经过市场验证的开源 BI 系统推荐

以下是当前主流且经过市场验证的开源 BI 系统推荐&#xff0c;结合技术特性、适用场景和行业实践&#xff0c;为不同需求提供针对性解决方案&#xff1a;一、综合型开源 BI 平台1. Apache Superset&#xff08;Apache 2.0 协议&#xff09;核心优势&#xff1a;全场景覆盖&…

第05章 排序与分页

1.排序数据 1.1 排序规则 1.2 单列排序 1.3 多列排序 2.分页 2.1 背景 背景1:查询返回的记录太多了,查看起来很不方便,怎么样能够实现分页查询呢? 背景2:表里有 4 条数据,我们只想要显示第 2、3 条数据怎么办呢? 2.2 实现规则 分页原理:所谓分页显示,就是将数据…

第4章 程序段的反复执行4.2while语句P128练习题(题及答案)

&#xff08;&#xff08;1&#xff09;阅读程序#include <bits/stdc.h> using namespace std; //汤永红 int main(){int n,s0;cin >> n;while(n){s s * 10 n % 10;n / 10;}cout << s << endl;return 0; }分别输入&#xff1a;0 1024 1234567890输出…

Linux下管道的实现

1.温故知新在上一篇博客我们知道了动态库是怎么样进行链接的&#xff0c;我们知道我们的.o文件&#xff0c;可执行文件都是我们的ELF格式的文件&#xff0c;是ELF文件&#xff0c;里面就有ELF header&#xff0c;程序头表&#xff0c;节&#xff0c;还有节头表&#xff0c;我们…

光猫、路由器和交换机

光猫&#xff1a;全称为光调制解调器&#xff0c;负责光信号与电信号的转换。在光纤入户的网络环境中&#xff0c;运营商通过光纤传输光信号&#xff0c;光猫将其转换为电脑、路由器等设备能识别的电信号&#xff0c;反之亦然。它是用户端与运营商网络之间的桥梁&#xff0c;保…