当前位置: 首页 > 软件库 > 管理和监控 > 系统监控 >

dynamic-tp

轻量级动态线程池
授权协议 Apache
开发语言 Java JavaScript
所属分类 管理和监控、 系统监控
软件类型 开源软件
地区 国产
投 递 者 蒋永宁
操作系统 跨平台
开源组织
适用人群 未知
 软件概览

logo

基于配置中心的轻量级动态线程池,内置监控告警功能,可通过SPI自定义扩展实现

官网: https://dynamictp.cn ��


背景

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

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

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

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

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

如果看过 ThreadPoolExecutor 的源码,大概可以知道其实它有提供一些 set 方法,可以在运行时动态去修改相应的值,这些方法有:

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);
 

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

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

  • 广泛性:在 Java 开发中,想要提高系统性能,线程池已经是一个 90%以上的人都会选择使用的基础工具

  • 不确定性:项目中可能会创建很多线程池,既有 IO 密集型的,也有 CPU 密集型的,但线程池的参数并不好确定;需要有套机制在运行过程中动态去调整参数

  • 无感知性,线程池运行过程中的各项指标一般感知不到;需要有套监控报警机制在事前、事中就能让开发人员感知到线程池的运行状况,及时处理

  • 高可用性,配置变更需要及时推送到客户端;需要有高可用的配置管理推送服务,配置中心是现在大多数互联网系统都会使用的组件,与之结合可以大幅度减少开发量及接入难度


简介

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

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

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

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

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

  • 代码零侵入:所有配置都放在配置中心,对业务代码零侵入

  • 轻量简单:基于 springboot 实现,引入 starter,接入只需简单4步就可完成,顺利3分钟搞定

  • 高可扩展:框架核心功能都提供 SPI 接口供用户自定义个性化实现(配置中心、配置文件解析、通知告警、监控数据采集、任务包装等等)

  • 线上大规模应用:参考美团线程池实践,美团内部已经有该理论成熟的应用经验

  • 通知报警:提供多种报警维度(配置变更通知、活性报警、容量阈值报警、拒绝触发报警、任务执行或等待超时报警),已支持企业微信、钉钉、飞书报警,同时提供 SPI 接口可自定义扩展实现

  • 监控:定时采集线程池指标数据,支持通过 MicroMeter、JsonLog 日志输出、Endpoint 三种方式,可通过 SPI 接口自定义扩展实现

  • 任务增强:提供任务包装功能,实现TaskWrapper接口即可,如 TtlTaskWrapper 可以支持线程池上下文信息传递,以及给任务设置标识id,方便问题追踪

  • 兼容性:JUC 普通线程池也可以被框架监控,@Bean 定义时加 @DynamicTp 注解即可

  • 可靠性:框架提供的线程池实现 Spring 生命周期方法,可以在 Spring 容器关闭前尽可能多的处理队列中的任务

  • 多模式:参考Tomcat线程池提供了 IO 密集型场景使用的 EagerDtpExecutor 线程池

  • 支持多配置中心:基于主流配置中心实现线程池参数动态调整,实时生效,已支持 Nacos、Apollo、Zookeeper、Consul,同时也提供 SPI 接口可自定义扩展实现

  • 中间件线程池管理:集成管理常用第三方组件的线程池,已集成Tomcat、Jetty、Undertow、Dubbo、RocketMq、Hystrix等组件的线程池管理(调参、监控报警)


设计

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

1.配置变更监听模块

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

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

4.监控模块

5.通知告警模块

  • 配置变更监听模块

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

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

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

  • 服务内部线程池管理模块

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

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

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

  • 三方组件线程池管理

    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:该报警项累计总数

 

  • 前言     dynamic-tp是一个轻量级的动态线程池插件,它是一个基于配置中心的动态线程池,线程池的参数可以通过配置中心配置进行动态的修改,在配置中心的支持上最开始的时候支持Nacos和Apollo,由于笔者公司用的配置中心是Zookeeper,所以就想着扩展支持Zookeeper,在了解源码支持发现dynamic-tp的扩展能力做的很好,提供了扩展接口,只要我开发对应的配置中心模块即可,最

  • 前言     自从笔者给dynamic-tp接入了Zookeeper配置中心,就想着再扩展其他的配置中心,恰好笔者近期也在调研Consul配置中心,所以就想着将Consul配置中心接入到dynamic-tp。 dynamic-tp快速接入: dynamic-tp官网: 接入Consul配置中心具体实现     Consul配置中心是通过定时任务做的配置变更,为了屏蔽底层实现,这里我选择对Sprin

  • 建造职责链 public class NotifyFilterBuilder { private NotifyFilterBuilder() { } public static InvokerChain<BaseNotifyCtx> getAlarmInvokerChain() { val filters = ApplicationContextHolder.g

 相关资料
  • 主要内容:使用普通函数创建 goroutine,使用匿名函数创建goroutine在编写 Socket 网络程序时,需要提前准备一个线程池为每一个 Socket 的收发包分配一个线程。开发人员需要在线程数量和 CPU 数量间建立一个对应关系,以保证每个任务能及时地被分配到 CPU 上进行处理,同时避免多个任务频繁地在线程间切换执行而损失效率。 虽然,线程池为逻辑编写者提供了线程分配的抽象机制。但是,如果面对随时随地可能发生的并发和线程处理需求,线程池就不是非常直观和方便了。能否

  • 在常用的并发模型中,多进程、多线程、分布式是最普遍的,不过近些年来逐渐有一些语言以first-class或者library的形式提供对基于协程的并发模型的支持。其中比较典型的有Scheme、Lua、Python、Perl、Go等以first-class的方式提供对协程的支持。 同样地,Kotlin也支持协程。 本章我们主要介绍: 什么是协程 协程的用法实例 挂起函数 通道与管道 协程的实现原理 c

  • 动态编程方法类似于将问题分解为更小但更小的子问题的分而治之。 但不同的是,分而治之,这些子问题并没有独立解决。 相反,记住这些较小子问题的结果并用于类似或重叠的子问题。 动态编程用于我们遇到问题的地方,可以将其划分为类似的子问题,以便可以重复使用它们的结果。 大多数情况下,这些算法用于优化。 在解决现有子问题之前,动态算法将尝试检查先前解决的子问题的结果。 结合子问题的解决方案以实现最佳解决方案。

  • 问题内容: 我有一个运行时间很长的过程,可以监听事件并进行一些激烈的处理。 目前,我通常用于限制并发运行的作业数量,但是根据一天中的时间以及其他各种因素,我希望能够动态地增加或减少并发线程的数量。 如果我减少了并发线程的数量,那么我希望当前正在运行的作业能够很好地完成。 是否有Java库可以让我控制并动态增加或减少线程池中运行的并发线程数?(该类必须实现ExecutorService)。 我必须自

  • 到现在,我们已经将QML作为一个工具用来构造静态场景和静态场景的导航。根据不同的状态和逻辑规则,一个实时动态的用户界面已经被创建。通过使用QML和JavaScript以更加动态的方式,进一步的扩大灵活性。组件可以在运行时加载和实例化,元素能够被销毁。动态创建的用户界面能够被存储在磁盘上,并且恢复。

  • 动态绑定确定在运行时而不是在编译时调用的方法。 动态绑定也称为后期绑定。 在Objective-C中,所有方法都在运行时动态解析。 执行的确切代码由方法名称(选择器)和接收对象确定。 动态绑定可实现多态性。 例如,考虑一组对象,包括Rectangle和Square。 每个对象都有自己的printArea方法实现。 在下面的代码片段中,表达式[anObject printArea]应该执行的实际代码