持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第27天,点击查看活动详情
使用线程池ThreadPoolExecutor过程中你是否有以下痛点呢?
- 代码中创建了一个 ThreadPoolExecutor,但是不知道那几个核心参数设置多少比较合适
- 凭经验设置参数值,上线后发现需要调整,改代码重新发布服务,非常麻烦
- 线程池相对开发人员来说是个黑盒,运行情况不能及时感知到,直到出现问题
如果你有以上痛点,动态可监控线程池框架(DynamicTp)或许能帮助到你。
一、什么是动态可监控线程池框架(DynamicTp)
dynamic-tp是一个轻量级的动态线程池插件,它是一个基于配置中心的动态线程池,线程池的参数可以通过配置中心配置进行动态的修改,目前支持的配置中心有Apollo,Nacos和Zookeeper,同时dynamic-tp支持线程池的监控和报警。
二、动态可监控线程池DynamicTp的功能特性
-
基于Spring框架,现只支持SpringBoot项目使用,轻量级,引入 starter 即可使用
-
基于配置中心实现线程池参数动态调整,实时生效;集成主流配置中心,已支持 Nacos、Apollo,Zookeeper, 同时也提供 SPI 接口可自定义扩展实现
-
内置通知报警功能,提供多种报警维度(配置变更通知、活性报警、容量阈值报警、拒绝策略触发报警), 默认支持企业微信、钉钉报警,同时提供 SPI 接口可自定义扩展实现
-
内置线程池指标采集功能,支持通过 MicroMeter、JsonLog 日志输出、Endpoint 三种方式,可通过 SPI 接口自定义扩展实现
-
集成管理常用第三方组件的线程池,已集成 SpringBoot 内置 WebServer(tomcat、undertow、jetty)的线程池管理
-
Builder 提供TTL包装功能,生成的线程池支持上下文信息传递
三、DynamicTp的快速接入步骤
1.引入相应配置中心的maven 依赖
//非 spring-cloud 场景下的 nacos 应用接入用此依赖
<dependency>
<groupId>cn.dynamictp</groupId>
<artifactId>dynamic-tp-spring-boot-starter-nacos</artifactId>
<version>1.0.8</version>
</dependency>
//spring-cloud 场景下的 nacos 应用接入用此依赖
<dependency>
<groupId>cn.dynamictp</groupId>
<artifactId>dynamic-tp-spring-cloud-starter-nacos</artifactId>
<version>1.0.8</version>
</dependency>
2.配置中心配置线程池实例,线程池配置(yml 类型)
spring:
dynamic:
tp:
enabled: true
enabledBanner: true # 是否开启banner打印,默认true
enabledCollect: true # 是否开启监控指标采集,默认false
collectorTypes: micrometer,logging # 监控数据采集器类型(logging | micrometer | internal_logging),默认micrometer
logPath: /home/logs # 监控日志数据路径,默认 ${user.home}/logs,采集类型非logging不用配置
monitorInterval: 5 # 监控时间间隔(报警判断、指标采集),默认5s
nacos: # nacos配置,不配置有默认值(规则appname-dev.yml这样),cloud应用不需要配置
dataId: dynamic-tp-demo-dev.yml
group: DEFAULT_GROUP
apollo: # apollo配置,不配置默认拿apollo配置第一个namespace
namespace: dynamic-tp-demo-dev.yml
configType: yml # 配置文件类型,非cloud nacos 和 apollo需配置,其他不用配
platforms: # 通知报警平台配置
- platform: wechat
urlKey: 3a700-127-4bd-a798-c53d8b69c # 替换
receivers: test1,test2 # 接受人企微名称
- platform: ding
urlKey: f80dad441fcd655438f4a08dcd6a # 替换
secret: SECb5441fa6f375d5b9d21 # 替换,非sign模式可以没有此值
receivers: 18888888888 # 钉钉账号手机号
- platform: lark
urlKey: 0d944ae7-b24a-40 # 替换
receivers: test1,test2 # 接受人飞书名称/openid
tomcatTp: # tomcat webserver线程池配置
corePoolSize: 100
maximumPoolSize: 200
keepAliveTime: 60
jettyTp: # jetty weberver线程池配置
corePoolSize: 100
maximumPoolSize: 200
undertowTp: # undertow webserver线程池配置
corePoolSize: 100
maximumPoolSize: 200
keepAliveTime: 60
hystrixTp: # hystrix 线程池配置
- threadPoolName: hystrix1
corePoolSize: 100
maximumPoolSize: 200
keepAliveTime: 60
dubboTp: # dubbo 线程池配置
- threadPoolName: dubboTp#20880 # 名称规则:dubboTp + "#" + 协议端口
threadPoolAliasName: 测试线程池 # dubbo线程池
corePoolSize: 100
maximumPoolSize: 200
keepAliveTime: 60
notifyItems: # 报警项,不配置自动会按默认值配置(变更通知、容量报警、活性报警)
- type: capacity # 报警项类型,查看源码 NotifyTypeEnum枚举类
enabled: true
threshold: 80 # 报警阈值
platforms: [ding,wechat] # 可选配置,不配置默认拿上层platforms配置的所以平台
interval: 120 # 报警间隔(单位:s)
rocketMqTp: # rocketmq 线程池配置
- threadPoolName: group1#topic1 # 名称规则:group + "#" + topic
corePoolSize: 200
maximumPoolSize: 200
keepAliveTime: 60
executors: # 动态线程池配置,都有默认值,采用默认值的可以不配置该项,减少配置量
- threadPoolName: dtpExecutor1
threadPoolAliasName: 测试线程池 # 线程池别名
executorType: common # 线程池类型common、eager:适用于io密集型
corePoolSize: 6
maximumPoolSize: 8
queueCapacity: 200
queueType: VariableLinkedBlockingQueue # 任务队列,查看源码QueueTypeEnum枚举类
rejectedHandlerType: CallerRunsPolicy # 拒绝策略,查看RejectedTypeEnum枚举类
keepAliveTime: 50
allowCoreThreadTimeOut: false # 是否允许核心线程池超时
threadNamePrefix: test # 线程名前缀
waitForTasksToCompleteOnShutdown: false # 参考spring线程池设计,优雅关闭线程池
awaitTerminationSeconds: 5 # 单位(s)
preStartAllCoreThreads: false # 是否预热所有核心线程,默认false
runTimeout: 200 # 任务执行超时阈值,目前只做告警用,单位(ms)
queueTimeout: 100 # 任务在队列等待超时阈值,目前只做告警用,单位(ms)
taskWrapperNames: ["ttl"] # 任务包装器名称,集成TaskWrapper接口
notifyItems: # 报警项,不配置自动会按默认值配置(变更通知、容量报警、活性报警、拒绝报警、任务超时报警)
- type: capacity # 报警项类型,查看源码 NotifyTypeEnum枚举类
enabled: true
threshold: 80 # 报警阈值
platforms: [ding,wechat] # 可选配置,不配置默认拿上层platforms配置的所以平台
interval: 120 # 报警间隔(单位:s)
- type: change
enabled: true
- type: liveness
enabled: true
threshold: 80
- type: reject
enabled: true
threshold: 1
- type: run_timeout
enabled: true
threshold: 1
- type: queue_timeout
enabled: true
threshold: 1
3.启动类加 @EnableDynamicTp 注解
4.创建线程池,会注册到dynamic-tp。使用 @DynamicTp 或 DtpExecutor 进行注册,或通过 DtpRegistry.getDtpExecutor("name")获取。
普通 JUC 线程池想要被监控,可以 @Bean 定义时加 @DynamicTp 注解。
@Configuration
public class ThreadPoolConfiguration {
@DynamicTp("commonExecutor")
@Bean
public ThreadPoolExecutor commonExecutor() {
return (ThreadPoolExecutor) Executors.newFixedThreadPool(1);
}
@Bean
public DtpExecutor dtpExecutor() {
return ThreadPoolCreator.createDynamicFast("dynamic-tp-test-1");
}
@Bean
public ThreadPoolExecutor threadPoolExecutor() {
return ThreadPoolBuilder.newBuilder()
.threadPoolName("dynamic-tp-test-2")
.corePoolSize(10)
.maximumPoolSize(15)
.keepAliveTime(15000)
.timeUnit(TimeUnit.MILLISECONDS)
.workQueue(QueueTypeEnum.SYNCHRONOUS_QUEUE.getName(), null, false)
.buildDynamic();
}
}
四、DynamicTp接入启动日志输出
服务启动看到有如下日志输出说明接入成功:
tips:
动态线程池实例服务启动时会根据配置中心的配置动态注册到Spring容器中,建议不要用@Bean编程式重复声明同一线程池实例,直接配置在配置中心就行