前言

dynamic-tp是一个轻量级的动态线程池插件,它是一个基于配置中心的动态线程池,线程池的参数可以通过配置中心配置进行动态的修改,目前支持的配置中心有Apollo,NacosZookeeper,同时dynamic-tp支持线程池的监控和报警,具体特性如下:

  • 基于Spring框架,现只支持SpringBoot项目使用,轻量级,引入 starter 即可使用

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

  • 内置通知报警功能,提供多种报警维度(配置变更通知、活性报警、容量阈值报警、拒绝策略触发报警), 默认支持企业微信、钉钉报警,同时提供 SPI 接口可自定义扩展实现

  • 内置线程池指标采集功能,支持通过 MicroMeter、JsonLog 日志输出、Endpoint 三种方式,可通过 SPI 接口自定义扩展实现

  • 集成管理常用第三方组件的线程池,已集成 SpringBoot 内置 WebServer(tomcat、undertow、jetty)的线程池管理

  • Builder 提供TTL包装功能,生成的线程池支持上下文信息传递

具体介绍及使用方式

为了方便用户快速接入,笔者这里对Zookeeper配置中心接入做一个详细的介绍,其他配置中心的demo示例可以参考项目的example,该模块也是笔者贡献的。这里我会详细的介绍Zookeeper配置中心的接入和对接监控平台PrometheusGrafana

快速开始

pom依赖

dynamic-tp-spring-boot-starter-zookeeper是集成dynamic-tp的starter,这里引入了micrometer-registry-prometheusspring-boot-starter-actuator用于对接Prometheus

    <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></dependency><dependency><groupId>io.github.lyh200</groupId><artifactId>dynamic-tp-spring-boot-starter-zookeeper</artifactId><version>1.0.2</version></dependency><dependency><groupId>io.micrometer</groupId><artifactId>micrometer-registry-prometheus</artifactId><version>1.6.4</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency></dependencies>

YML配置

server:port: 8888spring:application:name: dynamic-tp-zookeeper-demo# 下面是接入zk配置中心的配置  dynamic:tp:config-type: properties # zookeeper只支持properties配置zookeeper:config-version: 1.0.0 # 配置版本号zk-connect-str: 127.0.0.1:2181 # zk配置中心,如果是集群用逗号分开root-node: /configserver/userproject # 项目节点node: dynamic-tp-zookeeper-demo # 配置文件节点
# 对接prometheus
management:metrics:tags:application: ${spring.application.name}endpoints:web:exposure:include: '*'

配置中心dynamic-tp-zookeeper-demo配置文件配置

注:Zookeeper配置中心只支持properties类型配置,配置示例如下:

spring.dynamic.tp.executors部分是对线程池的配置,该配置是数组类型,可以定义多个线程池
spring.dynamic.tp.executors[1].notifyItems部分配置是对线程池报警平台的配置,可以配置多个报警平台

# 开启动态线程池
spring.dynamic.tp.enabled=true
# 打印动态线程池banner
spring.dynamic.tp.enabledBanner=true
# 开启线程池监控指标收集
spring.dynamic.tp.enabledCollect=true
# 线程池监控指标收集类型 logging-日志文件 micrometer-采集到第三方平台
spring.dynamic.tp.collectorType=logging
# 采集监控数据时间间隔 5s
spring.dynamic.tp.monitorInterval=5
spring.dynamic.tp.executors[0].threadPoolName=dynamic-tp-test-1
spring.dynamic.tp.executors[0].corePoolSize=50
spring.dynamic.tp.executors[0].maximumPoolSize=50
spring.dynamic.tp.executors[0].queueCapacity=3000
spring.dynamic.tp.executors[0].queueType=VariableLinkedBlockingQueue
spring.dynamic.tp.executors[0].rejectedHandlerType=CallerRunsPolicy
spring.dynamic.tp.executors[0].keepAliveTime=50
spring.dynamic.tp.executors[0].allowCoreThreadTimeOut=false
spring.dynamic.tp.executors[0].threadNamePrefix=test1
spring.dynamic.tp.executors[0].notifyItems[0].type=capacity
spring.dynamic.tp.executors[0].notifyItems[0].enabled=false
spring.dynamic.tp.executors[0].notifyItems[0].threshold=80
spring.dynamic.tp.executors[0].notifyItems[0].platforms[0]=ding
spring.dynamic.tp.executors[0].notifyItems[0].platforms[1]=wechat
spring.dynamic.tp.executors[0].notifyItems[0].interval=120
spring.dynamic.tp.executors[0].notifyItems[1].type=change
spring.dynamic.tp.executors[0].notifyItems[1].enabled=false
spring.dynamic.tp.executors[0].notifyItems[2].type=liveness
spring.dynamic.tp.executors[0].notifyItems[2].enabled=false
spring.dynamic.tp.executors[0].notifyItems[2].threshold=80
spring.dynamic.tp.executors[0].notifyItems[3].type=reject
spring.dynamic.tp.executors[0].notifyItems[3].enabled=false
spring.dynamic.tp.executors[0].notifyItems[3].threshold=1
spring.dynamic.tp.executors[1].threadPoolName=dynamic-tp-test-2
spring.dynamic.tp.executors[1].corePoolSize=20
spring.dynamic.tp.executors[1].maximumPoolSize=30
spring.dynamic.tp.executors[1].queueCapacity=1000
spring.dynamic.tp.executors[1].queueType=VariableLinkedBlockingQueue
spring.dynamic.tp.executors[1].rejectedHandlerType=CallerRunsPolicy
spring.dynamic.tp.executors[1].keepAliveTime=50
spring.dynamic.tp.executors[1].allowCoreThreadTimeOut=false
spring.dynamic.tp.executors[1].threadNamePrefix=test2
spring.dynamic.tp.executors[1].notifyItems[0].type=capacity
spring.dynamic.tp.executors[1].notifyItems[0].enabled=false
spring.dynamic.tp.executors[1].notifyItems[0].threshold=80
spring.dynamic.tp.executors[1].notifyItems[0].platforms[0]=ding
spring.dynamic.tp.executors[1].notifyItems[0].platforms[1]=wechat
spring.dynamic.tp.executors[1].notifyItems[0].interval=120
spring.dynamic.tp.executors[1].notifyItems[1].type=change
spring.dynamic.tp.executors[1].notifyItems[1].enabled=false
spring.dynamic.tp.executors[1].notifyItems[2].type=liveness
spring.dynamic.tp.executors[1].notifyItems[2].enabled=false
spring.dynamic.tp.executors[1].notifyItems[2].threshold=80
spring.dynamic.tp.executors[1].notifyItems[3].type=reject
spring.dynamic.tp.executors[1].notifyItems[3].enabled=false
spring.dynamic.tp.executors[1].notifyItems[3].threshold=1

创建线程池

创建线程池,会注册到dynamic-tp

@Configuration
public class ThreadPoolConfiguration {@Beanpublic DtpExecutor dtpExecutor() {return ThreadPoolCreator.createDynamicFast("dynamic-tp-test-1");}@Beanpublic 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();}
}

使用

初次使用不注意官网文档的话可能会通过@Autowired的方式使用,目前版本这么使用是不正确的,因为当读取配置文件后,配置文件生成的线程池对象就会把@Bean创建的线程池覆盖了,所以目前版本只能根据名字从DtpRegistry获取线程池对象了,笔者也和项目作者沟通过,项目作者也觉得通过@Autowired方式更好一些,后面版本也会优化。

@Slf4j
@RestController
@SuppressWarnings("all")
public class TestController {@GetMapping("/dtp-zookeeper-example/test")public String test() {new Thread(() -> {try {task();} catch (InterruptedException e) {e.printStackTrace();}}).start();return "success";}public void task() throws InterruptedException {DtpExecutor dtpExecutor1 = DtpRegistry.getExecutor("dynamic-tp-test-1");DtpExecutor dtpExecutor2 = DtpRegistry.getExecutor("dynamic-tp-test-2");for (int i = 0; i < 100; i++) {Thread.sleep(100);dtpExecutor1.execute(() -> {log.info("i am dynamic-tp-test-1 task");});dtpExecutor2.execute(() -> {log.info("i am dynamic-tp-test-2 task");});}}
}

监控数据和第三方平台对接

logging方式

spring.dynamic.tp.collectorType=logging,logging方式的监控数据,采集日志文件中,文件的位置可以通过spring.dynamic.tp.logPath配置,默认 ${user.home}/logs,日志内容如下:

2022-03-07 13:48:31.585 INFO [dtp-monitor1:D.M.LOG] {"activeCount":0,"queueSize":0,"largestPoolSize":0,"poolSize":0,"rejectHandlerName":"CallerRunsPolicy","queueCapacity":0,"fair":false,"rejectCount":0,"waitTaskCount":0,"taskCount":0,"queueRemainingCapacity":0,"corePoolSize":40,"queueType":"SynchronousQueue","completedTaskCount":0,"dtpName":"dynamic-tp-test-2","maximumPoolSize":55}
2022-03-07 13:48:31.585 INFO [dtp-monitor1:D.M.LOG] {"activeCount":0,"queueSize":0,"largestPoolSize":0,"poolSize":0,"queueCapacity":2147483647,"fair":false,"rejectCount":0,"waitTaskCount":0,"taskCount":0,"queueRemainingCapacity":2147483647,"corePoolSize":10,"queueType":"TaskQueue","completedTaskCount":0,"dtpName":"tomcatWebServerTp","maximumPoolSize":200}
2022-03-07 13:48:36.590 INFO [dtp-monitor1:D.M.LOG] {"activeCount":0,"queueSize":0,"largestPoolSize":0,"poolSize":0,"rejectHandlerName":"CallerRunsPolicy","queueCapacity":1024,"fair":false,"rejectCount":0,"waitTaskCount":0,"taskCount":0,"queueRemainingCapacity":1024,"corePoolSize":50,"queueType":"VariableLinkedBlockingQueue","completedTaskCount":0,"dtpName":"dynamic-tp-test-1","maximumPoolSize":50}
2022-03-07 13:48:36.590 INFO [dtp-monitor1:D.M.LOG] {"activeCount":0,"queueSize":0,"largestPoolSize":0,"poolSize":0,"rejectHandlerName":"CallerRunsPolicy","queueCapacity":0,"fair":false,"rejectCount":0,"waitTaskCount":0,"taskCount":0,"queueRemainingCapacity":0,"corePoolSize":40,"queueType":"SynchronousQueue","completedTaskCount":0,"dtpName":"dynamic-tp-test-2","maximumPoolSize":55}
2022-03-07 13:48:36.590 INFO [dtp-monitor1:D.M.LOG] {"activeCount":0,"queueSize":0,"largestPoolSize":0,"poolSize":0,"queueCapacity":2147483647,"fair":false,"rejectCount":0,"waitTaskCount":0,"taskCount":0,"queueRemainingCapacity":2147483647,"corePoolSize":10,"queueType":"TaskQueue","completedTaskCount":0,"dtpName":"tomcatWebServerTp","maximumPoolSize":200}

MicroMeter方式

spring.dynamic.tp.collectorType=micrometer 采集数据到第三方平台,这里使用的是Prometheus。可视化展示需要在Grafana平台配置,数据源选择Prometheus,然后创建Dashboard,先要在Dashboard配置动态的参数Variables,如下图:

配置完参数后,我们创建Panel,可以创建多个Panel,然后配置Panel的数据查询,报警显示等等,如下图:

最终的Dashboard如下图:

总结

促使我使用dynamic-tp的一个最主要的点就是它轻量级,提供了线程池监控、报警、基于配置中心修改线程池参数功能,完全满足了我在业务中的需要,同时监控数据能够对接公司现有的监控平台(Prometheus+Grafana),并且在使用上也十分方便,我在刚接触这个插件的时候它还不支持Zookeeper,恰好我司使用的配置中心就是Zookeeper,因为我在此基础上把Zookeeper配置中心集成到了dynamic-tp并贡献给社区,希望可以帮到更多的人,下一篇简单介绍下dynamic-tp支持Zookeeper的实现细节。

动态线程池dynamic-tp快速接入相关推荐

  1. 轻量级动态线程池才是“王道”?

    一.前言 最初设计 Hippo4j 的初衷是尽可能提高以及保障线程池对于线上应用的作用,所以加了很多个性化功能,这也间接导致强依赖 Hippo4j Server 项目. 自 Hippo4j 1.0.0 ...

  2. 美团动态线程池实践思路,开源了

    大家好,今天我们来聊一个比较实用的话题,动态可监控的线程池实践,全新开源项目(DynamicTp)地址在文章末尾,欢迎交流学习. 写在前面 稍微有些Java编程经验的小伙伴都知道,Java的精髓在ju ...

  3. 美团动态线程池实践思路已开源

    项目地址 gitee地址:gitee.com/yanhom/dyna- github地址:github.com/lyh200/dyna- 系列文章 动态线程池框架(DynamicTp),监控及源码解析 ...

  4. 美团动态线程池实践思路开源项目(DynamicTp),线程池源码解析及通知告警篇

    大家好,这篇文章我们来聊下动态线程池开源项目(DynamicTp)的通知告警模块.目前项目提供以下通知告警功能,每一个通知项都可以独立配置是否开启.告警阈值.告警间隔时间.平台等,具体代码请看core ...

  5. 【开源项目】动态线程池框架Hippo4j源码解析

    动态线程池框架Hippo4j源码解析 项目简介 Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池等功能,为业务系统提高线上运行保障能力. 快速开始 https://hippo4 ...

  6. 给你介绍下,Hippo4J 动态线程池基础架构

    很多小伙伴知道小编从今年六月份开始,陆陆续续开始提交 Hippo4J 动态线程池项目 经过 200+ 的 Commit,也是快要能发布 1.0.0 正式版本,今天就写一篇文章正式介绍下 Hippo4J ...

  7. Hippo4j和DynamicTp动态线程池介绍和使用中遇到的坑

    文章目录 @[toc] 1.前言 1.1Dromara致力于微服务云原生解决方案的组织 1.2 动态线程池的思路 1.3Hippo4j和DynamicTp动态线程池解决什么痛点 2.介绍 2.1Hip ...

  8. 借鉴美团文章实现的动态线程池,已开源

    大家好, 我是龙台 给自己定了个小目标,hippo4j 年底达到 1k star! GitHub:https://github.com/acmenlt/dynamic-threadpool Site: ...

  9. 美团简单版动态线程池源码实现

    背景 动态线程池,指的是线程池中的参数可以动态修改并生效,比如corePoolSize.maximumPoolSize等. 在工作中,线程池的核心线程数和最大线程数等参数是很难估计和固定的,如果能在应 ...

最新文章

  1. qt webassembly 安装过程记录及注意事项
  2. deploy service on swarm
  3. python 制作高斯mask_【趣味案例】用Python制作各种酷炫词云图,原来这么简单!...
  4. Mac下使用OpenCV
  5. 整数加扰java_生成随机顺序,但在java中有约束
  6. 好中的图像处理方面的期刊_约会中,注意这四个方面,帮助你把握好自己的真爱...
  7. Web项目替换jar包中的文件的方法
  8. python小孩的报酬_孩子做了家务,家长该不该支付“酬劳”呢?
  9. Spring Boot jackson配置使用详解
  10. 用VBScript实现Zip压缩目录中的所有文件
  11. java 比较2个时间大小写_date - Java 8:计算两个LocalDateTime之间的差异
  12. python删除文件夹无法访问_Python:pip和mu安装第三方库的小麻烦及解决方法
  13. 20171201-构建之法:现代软件工程-阅读笔记
  14. 实践项目2 图书管理系统
  15. 支付宝支付提示 4006 ISV权限不足,建议在开发者中心检查签约是否已经生效
  16. IAST 技术进阶系列(二):全场景多核驱动
  17. CASS11.0.0.6安装以及教程
  18. python正态检验_Python的数据正态性检验
  19. Springboot整合支付宝支付(沙箱)
  20. “小镇青年”、“互联网老兵”、“币圈韭菜” 玉红的众多标签为哪般?

热门文章

  1. PowerDesigner 教程
  2. 5 个免费的 Web 视频及音频播放器
  3. Android 组件化最佳实践 ARetrofit原理
  4. 05-linux日志管理-04-journalctl 命令(查询、日志清理、大小限制)
  5. C++挖掘程序本质(第二章C++面向对象-上)李明杰-M了个J 配套教材
  6. CMP Facade DataSet 数据集 | 建筑物正面数据集 | 云盘分享 |
  7. java中10》》2_(10*(2-8)+10)/(5-5*2)在JAVA语言中,上面的表达式计算结果为(选一项)_学小易找答案...
  8. 枚举类的特殊使用规范
  9. qt开发的有界面的简易对战游戏——斗罗大PK(可用作c,c++课程设计)
  10. C++ 中的 static 关键字