初识动态线程池dynamic-tp

642 阅读6分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第27天,点击查看活动详情

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

  • 代码中创建了一个 ThreadPoolExecutor,但是不知道那几个核心参数设置多少比较合适
  • 凭经验设置参数值,上线后发现需要调整,改代码重新发布服务,非常麻烦
  • 线程池相对开发人员来说是个黑盒,运行情况不能及时感知到,直到出现问题

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

一、什么是动态可监控线程池框架(DynamicTp

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

二、动态可监控线程池DynamicTp的功能特性

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

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

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

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

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

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

三、DynamicTp的快速接入步骤

1.引入相应配置中心的maven 依赖

//非 spring-cloud 场景下的 nacos 应用接入用此依赖
    <dependency>
        <groupId>cn.dynamictp</groupId>
        <artifactId>dynamic-tp-spring-boot-starter-nacos</artifactId>
        <version>1.0.8</version>
    </dependency>
//spring-cloud 场景下的 nacos 应用接入用此依赖
    <dependency>
        <groupId>cn.dynamictp</groupId>
        <artifactId>dynamic-tp-spring-cloud-starter-nacos</artifactId>
        <version>1.0.8</version>
    </dependency>

2.配置中心配置线程池实例,线程池配置(yml 类型)

spring:
  dynamic:
    tp:
      enabled: true
      enabledBanner: true           # 是否开启banner打印,默认true
      enabledCollect: true          # 是否开启监控指标采集,默认false
      collectorTypes: micrometer,logging     # 监控数据采集器类型(logging | micrometer | internal_logging),默认micrometer
      logPath: /home/logs           # 监控日志数据路径,默认 ${user.home}/logs,采集类型非logging不用配置
      monitorInterval: 5            # 监控时间间隔(报警判断、指标采集),默认5s
      nacos:                        # nacos配置,不配置有默认值(规则appname-dev.yml这样),cloud应用不需要配置
        dataId: dynamic-tp-demo-dev.yml
        group: DEFAULT_GROUP
      apollo:                       # apollo配置,不配置默认拿apollo配置第一个namespace
        namespace: dynamic-tp-demo-dev.yml
      configType: yml               # 配置文件类型,非cloud nacos 和 apollo需配置,其他不用配
      platforms:                    # 通知报警平台配置
        - platform: wechat
          urlKey: 3a700-127-4bd-a798-c53d8b69c     # 替换
          receivers: test1,test2                   # 接受人企微名称
        - platform: ding
          urlKey: f80dad441fcd655438f4a08dcd6a     # 替换
          secret: SECb5441fa6f375d5b9d21           # 替换,非sign模式可以没有此值
          receivers: 18888888888                   # 钉钉账号手机号
        - platform: lark
          urlKey: 0d944ae7-b24a-40                 # 替换
          receivers: test1,test2                   # 接受人飞书名称/openid
      tomcatTp:                                    # tomcat webserver线程池配置
        corePoolSize: 100
        maximumPoolSize: 200
        keepAliveTime: 60
      jettyTp:                                     # jetty weberver线程池配置
        corePoolSize: 100
        maximumPoolSize: 200
      undertowTp:                                  # undertow webserver线程池配置
        corePoolSize: 100
        maximumPoolSize: 200
        keepAliveTime: 60
      hystrixTp:                                   # hystrix 线程池配置
        - threadPoolName: hystrix1
          corePoolSize: 100
          maximumPoolSize: 200
          keepAliveTime: 60
      dubboTp:                                     # dubbo 线程池配置
        - threadPoolName: dubboTp#20880            # 名称规则:dubboTp + "#" + 协议端口
          threadPoolAliasName: 测试线程池             # dubbo线程池
          corePoolSize: 100
          maximumPoolSize: 200
          keepAliveTime: 60
          notifyItems:                             # 报警项,不配置自动会按默认值配置(变更通知、容量报警、活性报警)
            - type: capacity                       # 报警项类型,查看源码 NotifyTypeEnum枚举类
              enabled: true
              threshold: 80                        # 报警阈值
              platforms: [ding,wechat]             # 可选配置,不配置默认拿上层platforms配置的所以平台
              interval: 120                        # 报警间隔(单位:s)
      rocketMqTp:                                  # rocketmq 线程池配置
        - threadPoolName: group1#topic1            # 名称规则:group + "#" + topic
          corePoolSize: 200
          maximumPoolSize: 200
          keepAliveTime: 60
      executors:                                   # 动态线程池配置,都有默认值,采用默认值的可以不配置该项,减少配置量
        - threadPoolName: dtpExecutor1
          threadPoolAliasName: 测试线程池             # 线程池别名
          executorType: common                     # 线程池类型common、eager:适用于io密集型
          corePoolSize: 6
          maximumPoolSize: 8
          queueCapacity: 200
          queueType: VariableLinkedBlockingQueue   # 任务队列,查看源码QueueTypeEnum枚举类
          rejectedHandlerType: CallerRunsPolicy    # 拒绝策略,查看RejectedTypeEnum枚举类
          keepAliveTime: 50
          allowCoreThreadTimeOut: false                  # 是否允许核心线程池超时
          threadNamePrefix: test                         # 线程名前缀
          waitForTasksToCompleteOnShutdown: false        # 参考spring线程池设计,优雅关闭线程池
          awaitTerminationSeconds: 5                     # 单位(s)
          preStartAllCoreThreads: false                  # 是否预热所有核心线程,默认false
          runTimeout: 200                                # 任务执行超时阈值,目前只做告警用,单位(ms)
          queueTimeout: 100                              # 任务在队列等待超时阈值,目前只做告警用,单位(ms)
          taskWrapperNames: ["ttl"]                      # 任务包装器名称,集成TaskWrapper接口
          notifyItems:                     # 报警项,不配置自动会按默认值配置(变更通知、容量报警、活性报警、拒绝报警、任务超时报警)
            - type: capacity               # 报警项类型,查看源码 NotifyTypeEnum枚举类
              enabled: true
              threshold: 80                # 报警阈值
              platforms: [ding,wechat]     # 可选配置,不配置默认拿上层platforms配置的所以平台
              interval: 120                # 报警间隔(单位:s)
            - type: change
              enabled: true
            - type: liveness
              enabled: true
              threshold: 80
            - type: reject
              enabled: true
              threshold: 1
            - type: run_timeout
              enabled: true
              threshold: 1
            - type: queue_timeout
              enabled: true
              threshold: 1

3.启动类加 @EnableDynamicTp 注解

4.创建线程池,会注册到dynamic-tp。使用 @DynamicTp 或 DtpExecutor 进行注册,或通过 DtpRegistry.getDtpExecutor("name")获取。

普通 JUC 线程池想要被监控,可以 @Bean 定义时加 @DynamicTp 注解。

@Configuration
public class ThreadPoolConfiguration {


    @DynamicTp("commonExecutor")
    @Bean
    public ThreadPoolExecutor commonExecutor() {
        return (ThreadPoolExecutor) Executors.newFixedThreadPool(1);
    }

    @Bean
    public DtpExecutor dtpExecutor() {

        return ThreadPoolCreator.createDynamicFast("dynamic-tp-test-1");
    }

    @Bean
    public 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();
    }
}

四、DynamicTp接入启动日志输出

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

image.png

tips:

动态线程池实例服务启动时会根据配置中心的配置动态注册到Spring容器中,建议不要用@Bean编程式重复声明同一线程池实例,直接配置在配置中心就行