「使用线程池 ThreadPoolExecutor 过程中你是否有以下痛点呢?」
- 代码中创建了一个
ThreadPoolExecutor,但是不知道那几个核心参数设置多少比较合适
- 凭经验设置参数值,上线后发现需要调整,改代码重启服务,非常麻烦
- 线程池相对开发人员来说是个黑盒,运行情况不能及时感知到,直到出现问题
如果你有以上痛点,动态可监控线程池(DynamicTp)或许能帮助到你。
背景
如果看过 ThreadPoolExecutor 的源码,大概可以知道它对核心参数基本都有提供 set / get 方法以及一些扩展方法,可以在运行时动态修改、获取相应的值。
现在大多数互联网项目都已微服务化部署,拥有一套自己的服务治理体系。微服务组件中的分布式配置中心扮演的正是动态修改配置、实时生效的角色。那么我们是否可以结合配置中心来做运行时线程池参数的动态调整呢?答案是肯定的。配置中心通常具备高可用性,使用它无需过度担心配置推送失败,同时也能大幅降低研发动态线程池组件的难度和工作量。
「综上,可以总结出以下的背景」
- 「广泛性」:在 Java 开发中,想要提高系统性能与并发处理能力,线程池已是超过90%开发者会选择的基础工具。
- 「不确定性」:项目中可能创建多种线程池,包括IO密集型和CPU密集型,但参数难以确定;需要一套机制在运行过程中动态调整参数。
- 「无感知性」:线程池运行时的各项指标通常无法感知;需要一套监控报警机制,让开发人员能在事前、事中及时了解线程池状态并处理。
- 「高可用性」:配置变更需及时推送到客户端;高可用的配置管理推送服务是基础,结合现有配置中心可极大减少开发量和接入难度。
简介
「基于以上背景,我们对线程池 ThreadPoolExecutor 进行扩展增强,主要实现以下目标」
- 实现对运行中线程池参数的动态修改,实时生效。
- 实时监控线程池运行状态,触发预设报警策略时,将报警信息推送至办公平台。
- 定时采集线程池指标数据,配合如 Grafana 等可视化监控平台进行大盘监控。
「经过多个版本迭代,目前最新版本 v1.0.9 具有以下特性」 ✅
- 「代码零侵入」:所有配置均置于配置中心,对业务代码零侵入。
- 「轻量简单」:基于 SpringBoot 实现,引入
starter,接入仅需4步,顺利的话3分钟即可完成。
- 「高可扩展」:框架核心功能均提供 SPI 接口供用户自定义实现(配置中心、配置文件解析、通知告警、监控数据采集、任务包装等)。
- 「线上大规模应用」:参考美团线程池实践,其内部已有该理论成熟的应用经验。
- 「多平台通知报警」:提供多维度报警(配置变更、活性、容量阈值、拒绝触发、任务执行或等待超时),已支持企业微信、钉钉、飞书、邮件报警,并提供 SPI 接口供自定义扩展。
- 「监控」:定时采集线程池指标数据,支持通过
MicroMeter、JsonLog 日志输出、Endpoint 三种方式,可通过 SPI 接口自定义扩展。
- 「任务增强」:提供任务包装功能,实现
TaskWrapper 接口即可,如 MdcTaskWrapper、TtlTaskWrapper、SwTraceTaskWrapper,支持线程池上下文信息传递。
- 「兼容性」:JUC 普通线程池和 Spring 中的
ThreadPoolTaskExecutor 也可被框架监控,@Bean 定义时加 @DynamicTp 注解即可。
- 「可靠性」:框架提供的线程池实现了 Spring 生命周期方法,可在 Spring 容器关闭前尽可能多地处理队列中的任务。
- 「多模式」:参考 Tomcat 线程池,提供了 IO 密集型场景使用的
EagerDtpExecutor 线程池。
- 「支持多配置中心」:基于主流配置中心实现线程池参数动态调整与实时生效,已支持
Nacos、Apollo、Zookeeper、Consul、Etcd,同时提供 SPI 接口可自定义扩展。
- 「中间件线程池管理」:集成管理常用第三方组件的线程池,已集成
Tomcat、Jetty、Undertow、Dubbo、RocketMq、Hystrix、Grpc 等组件的线程池管理(调参、监控报警)。
架构设计
框架功能大体可分为以下几个模块:
- 配置变更监听模块
- 服务内部线程池管理模块
- 三方组件线程池管理模块
- 监控模块
- 通知告警模块
代码结构

图1:DynamicTp 项目各模块结构
- 「adapter 模块」:主要适配第三方组件的线程池管理,目前已实现 SpringBoot 内置的三大 Web 容器(
Tomcat、Jetty、Undertow)、Dubbo、RocketMq、Hystrix、Grpc 的线程池管理,后续会接入更多常用组件。
- 「common 模块」:包含各模块通用的类,用于解耦依赖和代码复用。
- 「core 模块」:框架的核心代码,包括动态调整参数、监控报警以及串联整个项目流程。
- 「example 模块」:提供简单使用示例,方便使用者参考。
- 「extension 模块」:存放扩展功能实现,如基于 Redis 的流控扩展、邮件发送扩展、SkyWalking 上下文传递扩展等。
- 「logging 模块」:用于配置框架内部日志输出,目前主要用于输出线程池监控指标数据到指定文件。
- 「starter模块」:提供独立功能模块的依赖封装与自动配置。
配置变更监听模块
- 监听特定配置中心的指定配置文件(已实现
Nacos、Apollo、Zookeeper、Consul、Etcd),可通过内部提供的 SPI 接口扩展其他实现。
- 解析配置文件内容,内置实现
yml、properties、json 配置文件的解析,可通过内部提供的 SPI 接口扩展其他实现。
- 通知线程池管理模块实现参数的刷新。
服务内部线程池管理模块
- 服务启动时从配置中心拉取配置,生成线程池实例并注册到内部线程池注册中心以及 Spring 容器中。
- 接收配置监听模块的刷新事件,实现线程池参数的刷新。
- 代码中通过依赖注入(推荐)或
DtpRegistry.getDtpExecutor() 方法根据线程池名称获取线程池实例。
三方组件线程池管理
- 服务启动时获取第三方中间件的线程池,交由框架管理。
- 接收参数刷新、指标收集、通知报警等事件,并进行相应处理。
监控模块
实现监控指标采集与输出,默认提供以下三种方式,也可通过内部提供的 SPI 接口扩展其他实现:
- 默认实现
JsonLog 输出到磁盘,开发者可自行采集解析日志并存储展示。
MicroMeter 采集,引入相关依赖并暴露端点后采集指标数据,可结合 Grafana 制作监控大盘。
- 暴露自定义
Endpoint 端点(dynamic-tp),支持通过 HTTP 方式实时访问。
通知告警模块
对接办公平台实现通知告警,已支持钉钉、企微、飞书、邮件,可通过内部 SPI 接口扩展。通知告警类型包括:
- 线程池主要参数变更通知。
- 阻塞队列容量达到设置的告警阈值。
- 线程池活性达到设置的告警阈值。
- 触发拒绝策略告警(格式:A/B,A:报警区间累计数量,B:累计总数)。
- 任务执行超时告警(格式:A/B)。
- 任务等待超时告警(格式:A/B)。

图2:DynamicTp 整体技术架构与数据流
项目地址
希望这篇关于 DynamicTp 动态线程池的介绍能对你有所帮助。如果你想了解更多类似的 Java 后端架构与实践,欢迎访问 云栈社区 进行交流与学习。
|