美团动态线程池开源框架 DynamicTp

2022-12-19 16:40:01 +08:00
 yanhomlin

背景

使用线程池 ThreadPoolExecutor 过程中你是否有以下痛点呢?

1.代码中创建了一个 ThreadPoolExecutor ,但是不知道那几个核心参数设置多少比较合适

2.凭经验设置参数值,上线后发现需要调整,改代码重新发布服务,非常麻烦

3.线程池相对开发人员来说是个黑盒,运行情况不能及时感知到,直到出现问题

如果你有以上痛点,动态可监控线程池框架(DynamicTp)或许能帮助到你。

如果看过 ThreadPoolExecutor 的源码,大概可以知道它对核心参数基本都有提供 set / get 方法以及一些扩展方法,可以在运行时动态修改、获取相应的值,这些方法有:

public void setCorePoolSize(int corePoolSize);
public void setMaximumPoolSize(int maximumPoolSize);
public void setKeepAliveTime(long time, TimeUnit unit);
public void setThreadFactory(ThreadFactory threadFactory);
public void setRejectedExecutionHandler(RejectedExecutionHandler handler);
public void allowCoreThreadTimeOut(boolean value);

public int getCorePoolSize();
public int getMaximumPoolSize();
public long getKeepAliveTime(TimeUnit unit);
public BlockingQueue<Runnable> getQueue();
public RejectedExecutionHandler getRejectedExecutionHandler();
public boolean allowsCoreThreadTimeOut();

protected void beforeExecute(Thread t, Runnable r);
protected void afterExecute(Runnable r, Throwable t);

现在大多数的互联网项目其实都会微服务化部署,有一套自己的服务治理体系,微服务组件中的分布式配置中心扮演的就是动态修改配置, 实时生效的角色。那么我们是否可以结合配置中心来做运行时线程池参数的动态调整呢?答案是肯定的,而且配置中心相对都是高可用的, 使用它也不用过于担心配置推送出现问题这类事儿,而且也能减少研发动态线程池组件本身的难度和工作量。

综上,可以总结出以下的背景

特性

基于以上背景分析,我们对线程池 ThreadPoolExecutor 做一些扩展增强,主要实现以下目标

1.实现对运行中线程池参数的动态修改,实时生效

2.实时监控线程池的运行状态,触发设置的报警策略时报警,报警信息推送办公平台

3.定时采集线程池指标数据,配合像 grafana 这种可视化监控平台做大盘监控

经过多个版本的迭代,目前最新版本 v1.0.9 具有以下特性

架构设计

框架功能大体可以分为以下几个模块

1.配置变更监听模块

2.服务内部线程池管理模块

3.三方组件线程池管理模块

4.监控模块

5.通知告警模块

代码结构

1.adapter 模块:主要是适配一些第三方组件的线程池管理,目前已经实现的有 SpringBoot 内置的三大 web 容器( TTomcat 、Jetty 、Undertow )、Dubbo 、RocketMq 、Hystrix 、Grpc 、Motan 、Okhttp3 、Brpc 、Tars 的线程池管理,后续会接入其他常用组件的线程池管理。

2.common 模块:主要是一些各个模板都会用到的类,解耦依赖,复用代码,大家日常开发中可能也经常会这样做。

3.core 模块:该框架的核心代码都在这个模块里,包括动态调整参数,监控报警,以及串联整个项目流程都在此。

4.example 模块:提供一个简单使用示例,方便使用者参照

5.extension 模块:放一些扩展功能实现,比如基于 redis 的流控扩展、邮件发送扩展、skywalking 上下文传递扩展等

6.logging 模块:用于配置框架内部日志的输出,目前主要用于输出线程池监控指标数据到指定文件

7.starter 模块:提供独立功能模块的依赖封装、自动配置等相关。

配置变更监听模块

1.监听特定配置中心的指定配置文件(已实现 Nacos 、Apollo 、Zookeeper 、Consul 、Etcd ),可通过内部提供的 SPI 接口扩展其他实现

2.解析配置文件内容,内置实现 yml 、properties 、json 配置文件的解析,可通过内部提供的 SPI 接口扩展其他实现

3.通知线程池管理模块实现参数的刷新

服务内部线程池管理模块

1.服务启动时从配置中心拉取配置,生成线程池实例注册到内部线程池注册中心以及 Spring 容器中

2.接受配置监听模块的刷新事件,实现线程池参数的刷新

3.代码中通过依赖注入(推荐)或者 DtpRegistry.getDtpExecutor() 方法根据线程池名称来获取线程池实例

三方组件线程池管理

1.服务启动获取第三方中间件的线程池,被框架管理起来

2.接受参数刷新、指标收集、通知报警事件,进行相应的处理

监控模块

实现监控指标采集以及输出,默认提供以下三种方式,也可通过内部提供的 SPI 接口扩展其他实现

1.默认实现 JsonLog 输出到磁盘,可以自己采集解析日志,存储展示

2.MicroMeter 采集,引入 MicroMeter 相关依赖,暴露相关端点,采集指标数据,结合 Grafana 做监控大盘

3.暴雷自定义 Endpoint 端点( dynamic-tp ),可通过 http 方式实时访问

通知告警模块

对接办公平台,实现通知告警功能,已支持钉钉、企微、飞书、邮件,可通过内部提供的 SPI 接口扩展其他实现,通知告警类型如下

1.线程池主要参数变更通知

2.阻塞队列容量达到设置的告警阈值

3.线程池活性达到设置的告警阈值

4.触发拒绝策略告警,格式:A/B ,A:该报警项前后两次报警区间累加数量,B:该报警项累计总数

5.任务执行超时告警,格式:A/B ,A:该报警项前后两次报警区间累加数量,B:该报警项累计总数

6.任务等待超时告警,格式:A/B ,A:该报警项前后两次报警区间累加数量,B:该报警项累计总数

接入使用

使用步骤

1.引入相应配置中心的依赖,具体见官网 maven 依赖

2.配置中心配置线程池实例,配置示例见官网(给出的是全配置项,不用的可以删除)

3.启动类加 @EnableDynamicTp 注解

4.使用 @Resource 或 @Autowired 进行依赖注入,或通过 DtpRegistry.getDtpExecutor("name") 获取

5.通过以上 4 步就可以使用了,是不是感觉很简单啊

服务启动看到有如下日志输出说明接入成功

|  __ \                            (_) |__   __|
| |  | |_   _ _ __   __ _ _ __ ___  _  ___| |_ __
| |  | | | | | '_ \ / _` | '_ ` _ | |/ __| | '_ \
| |__| | |_| | | | | (_| | | | | | | | (__| | |_) |
|_____/ __, |_| |_|__,_|_| |_| |_|_|___|_| .__/
         __/ |                              | |
        |___/                               |_|
 :: Dynamic Thread Pool ::

DynamicTp register dtpExecutor, source: beanPostProcessor, executor: DtpMainPropWrapper(dtpName=dynamic-tp-test-1, corePoolSize=6, maxPoolSize=8, keepAliveTime=50, queueType=VariableLinkedBlockingQueue, queueCapacity=200, rejectType=RejectedCountableCallerRunsPolicy, allowCoreThreadTimeOut=false)

DtpRegistry initialization end, remote dtpExecutors: [dtpExecutor1, dtpExecutor2], local dtpExecutors: [ioIntensiveExecutor], local commonExecutors: [commonExecutor]

项目地址

目前累计 2.5k star ,欢迎了解使用。

官网https://dynamictp.cn

gitee 地址https://gitee.com/dromara/dynamic-tp

github 地址https://github.com/dromara/dynamic-tp

2001 次点击
所在节点    推广
4 条回复
allenzhangSB
2022-12-19 16:42:51 +08:00
是不是应该发到推广节点? 一个线程池隔三差五的推广下
DreamStar
2022-12-19 16:47:36 +08:00
升级一下 Java 版本, 用协程就不用搞这么多魔法操作了
dqzcwxb
2022-12-19 17:38:17 +08:00
@DreamStar #2 山中苦练武功数十载,出山却发现七步之外枪快七步之内枪又快又准
线程池管理要如同当年的 cms 调优一样被扫进历史的垃圾堆
Aloento
2022-12-19 20:50:12 +08:00
就在那依托答辩上使劲雕花

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/903527

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX