preface

Dynamic-tp is a lightweight plugin for dynamic thread pools. It is a dynamic thread pool based on the configuration center. The parameters of the thread pool can be dynamically modified through the configuration center configuration, currently supported by Apollo,Nacos and Zookeeper. Meanwhile, dynamic-TP supports thread pool monitoring and alarm as follows:

  • Based on the Spring framework, it only supports SpringBoot projects. It is lightweight and can be used by introducing starter

  • Dynamic adjustment of thread pool parameters based on configuration center takes effect in real time. Integrated mainstream configuration center, has supported Nacos, Apollo, Zookeeper, but also provides SPI interface can be customized extension implementation

  • Built-in notification alarm function, providing a variety of alarm dimensions (configuration change notification, active alarm, capacity threshold alarm, reject policy trigger alarm), default support for enterprise wechat, nail alarm, while providing SPI interface can be customized expansion implementation

  • The built-in thread pool indicator collection function can be implemented through MicroMeter, JsonLog log output, and Endpoint, and can be customized through the SPI interface

  • Integration Management Thread pools of common third-party components have been integrated with SpringBoot built-in WebServer (Tomcat, Undertow, and Jetty) thread pool management

  • The Builder provides TTL wrapping and the generated thread pool supports context information passing

For detailed introduction and usage, please refer to the official website

In order to facilitate users’ quick access, the author gives a detailed introduction to Zookeeper configuration center access. Other configuration center demo examples can refer to the example of the project. This module is also contributed by the author. Here I will introduce in detail the access and connection of the Monitoring platforms Prometheus and Grafana in the Zookeeper configuration center.

Quick start

Pom depends on

Dynamic-tp-spring-boot-starter-zookeeper is a starter that integrates dynamic-TP. In this system, micrometers-Registrie-Prometheus and Spring-boot-starter -actuator are used for interconnecting with 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>
Copy the code

YML configuration

server:
  port: 8888

spring:
  application:
    name: dynamic-tp-zookeeper-demo
  Here is the configuration to access the ZK configuration center
  dynamic:
    tp:
      config-type: properties Zookeeper only supports properties configuration
      zookeeper:
        config-version: 1.0. 0 Configure the version number
        zk-connect-str: 127.0. 01.: 2181 # zK configuration centers, separated by commas if cluster
        root-node: /configserver/userproject # Project Node
        node: dynamic-tp-zookeeper-demo # config file node
Dock # Prometheus
management:
  metrics:
    tags:
      application: ${spring.application.name}
  endpoints:
    web:
      exposure:
        include: The '*'
Copy the code

Configuration center Dynamic-tp-zookeeper-demo configuration file configuration

Note: The Zookeeper configuration center supports only the properties configuration. The following is an example:

Spring. Dynamic. Tp. The executors part is on the thread pool configuration, the configuration is an array type, you can define multiple thread pool spring. Dynamic. Tp. The executors. [1] notifyItems part of the configuration is the thread pool alarm platform configuration, Multiple alarm platforms can be configured

# enable dynamic thread pool
spring.dynamic.tp.enabled=true
# print dynamic thread pool banner
spring.dynamic.tp.enabledBanner=true
# enable thread pool monitoring metrics collection
spring.dynamic.tp.enabledCollect=true
Logging - Log files micrometer- Collected on third-party platforms
spring.dynamic.tp.collectorType=logging
The monitoring data collection interval is 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
Copy the code

Creating a thread pool

Create a thread pool that registers with dynamic-TP

@Configuration
public class ThreadPoolConfiguration {

    @Bean
    public DtpExecutor dtpExecutor(a) {

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

    @Bean
    public ThreadPoolExecutor threadPoolExecutor(a) {
        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(); }}Copy the code

use

This is not correct because when the configuration file is read, the thread pool object generated by the configuration file overwrites the thread pool created by the @bean. Therefore, the current version of DtpRegistry can only fetch thread pool objects by name from DtpRegistry. I have spoken to the project author, who thinks it is better to use @AutoWired, which will be optimized in a later version.

@Slf4j
@RestController
@SuppressWarnings("all")
public class TestController {

    @GetMapping("/dtp-zookeeper-example/test")
    public String test(a) {
        new Thread(() -> {
            try {
                task();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        return "success";
    }

    public void task(a) 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"); }); }}}Copy the code

Monitoring data is connected to third-party platforms

Logging ways

Spring. Dynamic. Tp collectorType = logging, logging methods of monitoring data, the acquisition of the log file and the location of the file can be spring. The dynamic. Tp. The logPath configuration, ${user.home}/logs

The 2022-03-07 13:48:31. 585 INFO [DTP - monitor1: D.M.L OG] {"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 will, "" completedTaskCount dtpName" : 0, "" :" dynamic - tp - test - 2 ", "maximumPoolSize: 55} 13:48:31 2022-03-07. 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","completed TaskCount":0,"dtpName":"tomcatWebServerTp","maximumPoolSize":200} 2022-03-07 13:48:36.590 INFO [TDP-Monitor1: d.m.log] {"activeCount":0,"queueSize":0,"largestPoolSize":0,"poolSize":0,"rejectHandlerName":"CallerRunsPolicy","queueCapacity":1 024,"fair":false,"rejectCount":0,"waitTaskCount":0,"taskCount":0,"queueRemainingCapacity":1024,"corePoolSize":50,"queueT ype":"VariableLinkedBlockingQueue","completedTaskCount":0,"dtpName":"dynamic-tp-test-1","maximumPoolSize":50} 2022-03-07 13:48:36. 590 INFO [DTP - monitor1: D.M.L OG] {"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 will, "" completedTaskCount dtpName" : 0, "" :" dynamic - tp - test - 2 ", "maximumPoolSize: 55} 13:48:36 2022-03-07. 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","completed TaskCount":0,"dtpName":"tomcatWebServerTp","maximumPoolSize":200}Copy the code

MicroMeter way

Spring. Dynamic. Tp. CollectorType = micrometer to collect data to the third party platform, Prometheus is used here. The visual display needs to be configured on Grafana platform, select Prometheus as the data source, and then create Dashboard. The dynamic parameter Variables should be configured on Dashboard first, as shown below:

After configuring the parameters, we create Panel, you can create multiple panels, and then configure Panel data query, alarm display, etc., as shown below:

The resulting Dashboard looks like this:

conclusion

One of the main reasons that motivated me to use Dynamic-TP was that it was lightweight, providing thread pool monitoring, alarm, and thread pool parameter modification based on configuration center, which fully met my business needs, and the monitoring data could be connected to the company’s existing monitoring platform (Prometheus+Grafana). In addition, it is very convenient to use. When I first came into contact with this plug-in, it did not support Zookeeper, and the configuration center used by our company happened to be Zookeeper. Based on this, I integrated the Zookeeper configuration center into dynamic-TP and contributed it to the community, hoping to help more people. The next article will briefly cover the implementation details of dynamic-TP support for Zookeeper.