Dynamic-TP动态线程池部署SOP
1、背景
A组在最近遇到线程池相关问题:
设备在凌晨2点自己重启,设备上线后下发大量任务给cos,导致触发拒绝策略海外AP环境带宽不够,导致大量设备断连建连,下发大量任务给cos,导致触发拒绝策略我们目前使用的JUC线程池内部状态是个黑盒,难以及时排查线程池情况,也无法根据调参去准确判断线程池状态
因此为了更好的感知线程池运行过程中的信息,及时将信息推送到开发人员,我们需要引入动态线程池框架
动态线程池框架目前使用比较多的是 dynamic-tp和hippo4J,这两者都是使用了美团的动态线程池思想,不同点有:
dynamic-tp是单体应用,可以直接使用在微服务上;
hippo4J是C/S架构,如果要使用,不仅需要在微服务中引用,也要单独设置一个server端,较为复杂dynamic-tp在社区中活跃度较高,在一些开发者社区上也是dynamic-tp的文章偏多,dynamic-tp官网上也有较多知识分享文档;
hippo4J的交流群不活跃,文档少,且有问题只能去github上面提issue
因此在开发过程中选择使用dynamic-tp
2、优点介绍
1.1、dynamic-tp框架有以下优点,其中我在引入时使用的有:
动态调参:使用该框架后,不需要手写修改参数的方法进行调参;代码零侵入:我们改变了线程池以往的使用姿势,所有配置均放在配置中心,服务启动时会从配置中心拉取配置生成线程池对象放到 Spring 容器中,使用时直接从 Spring 容器中获取,对业务代码零侵入;轻量简单:使用起来极其简单,引入相应依赖,接入只需简单 4 步就可完成,顺利 3 分钟搞定,相当丝滑;框架开发者使用JMH验证过,损耗很小,可以忽略不计。线程池监控与通知告警:提供多种通知告警维度(配置变更通知、活性报警、队列容量阈值报警、拒绝触发报警、任务执行或等待超时报警),触发配置阈值实时推送告警信息,已支持企微、钉钉、飞书、邮件、云之家报警,同时提供 SPI 接口可自定义扩展实现。本次接入还增加了接入到运维平台通知的方式。多配置中心支持:支持多种主流配置中心,包括 Nacos、Apollo、Zookeeper、Consul、Etcd、Polaris、ServiceComb,同时也提供 SPI 接口可自定义扩展实现;
在本次开发中我们使用的是nacos接入可靠性:依靠 Spring 生命周期管理,可以做到优雅关闭线程池,在 Spring 容器关闭前尽可能多的处理队列中的任务;
具体体现在配置中,默认启动。高可扩展:框架核心功能都提供 SPI 接口供用户自定义个性化实现(配置中心、配置文件解析、通知告警、监控数据采集、任务包装、拒绝策略等等)
1.2、其他优点并未使用,如果有兴趣请前往官网查看详细使用方式:
运行监控:定时采集线程池指标数据(20 多种指标,包含线程池维度、队列维度、任务维度、tps、tpxx 等),支持通过 MicroMeter、JsonLog、JMX 三种方式定时获取,也可以通过 SpringBoot Endpoint 端点实时获取最新指标数据,同时提供 SPI 接口可自定义扩展实现任务增强:提供任务包装功能(比 Spring 线程池任务包装更强大),实现 TaskWrapper 接口即可,如 MdcTaskWrapper、TtlTaskWrapper、SwTraceTaskWrapper、OpenTelemetryWrapper,可以支持线程池上下文信息传递
多模式:提供了增强线程池 DtpExecutor,IO 密集型场景使用的线程池 EagerDtpExecutor,调度线程池 ScheduledDtpExecutor,有序线程池 OrderedDtpExecutor,可以根据业务场景选择合适的线程池
兼容性:JUC 普通线程池和 Spring 中的 ThreadPoolTaskExecutor 也可以被框架管理,只需@Bean 定义时加 @DynamicTp 注解即可中间件线程池管理:集成管理常用第三方组件的线程池,已集成 Tomcat、Jetty、Undertow、Dubbo、RocketMq、Hystrix、Grpc、Motan、Okhttp3、Brpc、Tars、SofaRpc、RabbitMq、Liteflow 等组件的线程池管理(动态调参、监控、报警)
3、如何接入
本人在common中增加了一个maven工程,集成了Dynamic-TP的一些基本配置

3.1、接入步骤:(以cos服务为例)
需要注意的是,由于线上已经验证OK,所以新旧线程池不需要切换,新旧线程池开关可以关掉,旧线程池配置可以删除
pom文件新增引用复制

启动类加上@EnableDynamicTp@ComponentScan加上"team.ucs.dynamicthreadpool",“team.ucs.entity”,"team.ucs.kafka"的扫描

线上配置文件加上对应配置,以cos服务为例
(dynamic-tp配置较多,如果想学习或者是使用其他配置,则需要到dynamic-tp官网查看,当前引入的时候只保留我们需要的,一些配置默认是true但是我们不需要的话,也要显式的标为false)
接入后启动,日志中打印如下则代表创建成功

3.2、配置文件怎么配置?接入时具体怎么配置?
以cos服务为例
配置文件可以看做以下4个部分:线程池参数配置、通知平台的配置、告警阈值配置、杂项旧线程池和新线程池配置时需要一一对应,此时可以通过线程池名称对应实现。可以看到在cos服务中旧线程池和新线程池名称一样

线程池开关,上面的开关enableCosDTP是为了可以走不同逻辑,下面的开关enabled是为了开关线程池框架,节省资源通知平台,其中可以配置多个平台,平台可以通过platform对应配置文件中通知平台和框架内通知平台的联系,platformId为了方便告警项、线程池中配置对应的通知平台线程池配置,executors可以配置多个动态线程池,通过threadPoolName和旧线程池进行配对,其他请看 配置文件中告警项,可以在notifyItems配置,每个线程池都需要加上,具体配置请看配置文件解释。cos服务中动态线程池配置 目前只是一些需要的配置,其他的配置可以在dyanmic-tp官网上进行查看~
接入动态线程池时需要做到新旧线程池一一对应,方面接入以及后续删除旧线程池。
3.3、怎么在代码中使用引入的动态线程池?
以cos服务为例
按照上述步骤接入动态线程池按照上述步骤配置好线程池配置(推荐)目前可以通过工具类进行实现,以cos为例,如果合适可以直接放进dynamic-thread-pool中,如下


4、使用效果
使用后触发配置文件中的告警阈值,如果使用的是刚刚的devops通知平台通知,会在群中打印对应信息,且可以看到使用详情,其中详情页面需要鼠标左键按住才能上下滑动查看信息。

释义写一下


使用后进行参数调整,会立刻生效,且可以被通知到


使用后调整通知平台和告警项的相关信息,会立刻生效,但不会通过平台通知到
5、注意事项
目前dynamic-tp的告警限流不支持redis集群当前线上场景出现过触发告警后增加阈值,在未达到告警阈值时仍然会告警的情况,仍未解决JMH(java项目性能测试工具)发现线程池qps增大到1w及以上时,动态线程池带来的性能损耗会比较大(具体见官网)之前上线时为了保证微服务可用,会保留旧线程池的bean,当前线上运行良好,故不再需要保留旧线程池
推荐阅读
(showdoc)《怎么根据线程池预警对线程池参数做修改》(showdoc)《DynamicTP源码解析》(外网)《dynamic-tp官网》(外网)《Java线程池实现原理及其在美团业务中的实践》





