hippo4j线程池监控落地

1.前言

1.1 动态线程池的思路

Java线程池可以动态的参数就只有一下几个,无非就是搞一个界面可视化配置动态刷新、监控,告警、适配第三方框架使用的线程池、JDK原生的线程池等等,基本都是这种玩的:
 

1.2Hippo4j动态线程池解决什么痛点

   简单来讲就是要达到一个可视化、可动态、可观测和可实时监控告警的效果,为业务测使用了线程池保驾护航,让线上业务平稳运行,不至于由于各种线程池的参数设置不恰当在大流量的冲击下而无法轻松应对,需要根据业务请求的体量来调整线程池各种参数原先基本都需要改代码然后需要部署重启项目,这个可以说是不方便也不快捷和高效,有了动态线程接入即可轻松可视化配置管理各种线程池,动态修改实时感知刷新都不需要重启和修改业务代码等操作。
 

2.介绍

2.1Hippo4j的官网如下

https://hippo4j.cn/

2.2Hippo4j的架构

2.3.1架构

Hippo4j 从部署的角度上分为两种角色:Server 端和 Client 端。
Server 端是 Hippo4j 项目打包出的 Java 进程,功能包括用户权限、线程池监控以及执行持久化的动作。
Client 端指的是我们 SpringBoot 应用,通过引入 Hippo4j Starter Jar 包负责与 Server 端进行交互。

2.3.2运行模式

Hippo4j config:轻量级动态线程池管理,依赖 Nacos、Apollo、Zookeeper、ETCD、Polaris、Consul 等三方配置中心(任选其一)完成线程池参数动态变更,支持运行时报警、监控等功能。
 
Hippo4j server:前面部署就是无中间件依赖版本,需要部署部署 Hippo4j server 服务,通过可视化 Web 界面完成线程池的创建、变更以及查看,不依赖三方中间件。相比较 Hippo4j config,功能会更强大,但同时也引入了一定的复杂性。需要部署一个 Java 服务,以及依赖 MySQL 数据库。
 

2.3.3server控制台

 
控制台登录页面
 

2.3Hippo4j的工程目录结构

工程目录结构官网都有相应的说明,看工程模块的名字也大致可以猜测是啥功能的:

2.4基础组件

2.4.1Client 端

Hippo4j Client 端,通过引入 Hippo4j Starter Jar 包负责与 Server 端进行交互。比如拉取 Server 端线程池数据、动态更新线程池配置以及采集上报线程池运行时数据等。

2.4.2配置中心(Config)

配置中心位于 Server 端,它的主要作用是监控 Server 端线程池配置变更,实时通知到 Client 实例执行线程池变更流程。
代码设计基于 Nacos 1.x 版本的 长轮询以及异步 Servlet 机制 实现。

2.4.3注册中心(Discovery)

负责管理 Client 端(单机或集群)注册到 Server 端的实例,包括不限于实例注册、续约、过期剔除 等操作,代码基于 Eureka 源码实现。
注册中心管理 Client 端注册的实例,通过这些实例可以 实时获取线程池的运行时参数信息。
目前的设计是如此,不排除后续基于 Discovery 做更多的扩展。

2.4.4控制台(Console)

对接前端项目

2.4.1消息通知(Notify)

Hippo4j 内置了很多需要通知的事件,比如:线程池参数变更通知、线程池活跃度报警、拒绝策略执行报警以及阻塞队列容量报警等。
目前 Notify 已经接入了钉钉、企业微信和飞书,后续持续集成邮件、短信等通知渠道;并且,Notify 模块提供了消息事件的 SPI 方案,可以接受三方自定义的推送。
 

3.快速开始

3.1服务启动

使用 Docker 运行服务端,默认使用内置 H2 数据库,数据持久化到 Docker 容器存储卷中。
docker run -d -p 6691:6691 --name hippo4j-server hippo4j/hippo4j-server
如果没有 Docker,可以使用源码编译的方式,启动 Hippo4j-Server/Hippo4j-Bootstrap 模块下 ServerApplication 应用类。
启动示例项目,hippo4j-spring-boot-starter-example 模块下 ServerExampleApplication 应用类。
访问 Server 控制台,路径 http://localhost:6691/index.html,默认用户名密码:admin / 123456

3.2配置变更

访问控制台动态线程池菜单下线程池实例,修改动态线程池相关参数。
观察 Hippo4j-Example 控制台日志输出,日志输出包括不限于此信息即为成功。
2024-05-28 00:23:29.783  INFO 50322 --- [change.config_0] c.h.s.s.c.ServerThreadPoolDynamicRefresh : [message-consume] Dynamic thread pool change parameter.
    corePoolSize: 2 => 4
    maximumPoolSize: 6 => 12
    capacity: 1024 => 2048
    keepAliveTime: 9999 => 9999
    executeTimeOut: 800 => 3000
    rejectedType: SyncPutQueuePolicy => RunsOldestTaskPolicy
    allowCoreThreadTimeOut: true => true
另外,当 Client 集群部署时,可以修改某一个实例,或选择 全部修改 按钮,修改所有实例线程池信息。
 

3.3client配置

SpringBoot Pom 引入 Hippo4j Starter Jar。
<dependency>
    <groupId>cn.hippo4j</groupId>
    <artifactId>hippo4j-spring-boot-starter</artifactId>
    <version>1.4.3</version>
</dependency>
启动类上添加注解 @EnableDynamicThreadPool
@SpringBootApplication
@EnableDynamicThreadPool
public class ExampleApplication {
    public static void main(String[] args) {
        SpringApplication.run(ExampleApplication.class, args);
    }
}
SpringBoot 应用配置文件添加:
spring:
  profiles:
    active: dev
  application:
    # 服务端创建的项目 id 需要与 application.name 保持一致
    name: dynamic-threadpool-example
  dynamic:
    thread-pool:
      # 服务端地址
      server-addr: http://localhost:6691
      # 用户名
      username: admin
      # 密码
      password: 123456
      # 租户 id, 对应 tenant 表
      namespace: prescription
      # 项目 id, 对应 item 表
      item-id: ${spring.application.name}

3.4ThreadPoolExecutor适配

添加线程池配置类,通过 @DynamicThreadPool 注解修饰。threadPoolId 为服务端创建的线程池 ID。
package cn.hippo4j.example;

import cn.hippo4j.core.executor.DynamicThreadPool;
import cn.hippo4j.core.executor.support.ThreadPoolBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.ThreadPoolExecutor;

@Configuration
public class ThreadPoolConfig {

    @Bean
    @DynamicThreadPool
    public ThreadPoolExecutor messageConsumeDynamicExecutor() {
        String threadPoolId = "message-consume";
        ThreadPoolExecutor messageConsumeDynamicExecutor = ThreadPoolBuilder.builder()
                .threadFactory(threadPoolId)
                .threadPoolId(threadPoolId)
                .dynamicPool()
                .build();
        return messageConsumeDynamicExecutor;
    }

    @Bean
    @DynamicThreadPool
    public ThreadPoolExecutor messageProduceDynamicExecutor() {
        String threadPoolId = "message-produce";
        ThreadPoolExecutor messageProduceDynamicExecutor = ThreadPoolBuilder.builder()
                .threadFactory(threadPoolId)
                .threadPoolId(threadPoolId)
                .dynamicPool()
                .build();
        return messageProduceDynamicExecutor;
    }

}
通过 ThreadPoolBuilder 构建动态线程池,只有 threadFactory、threadPoolId 为必填项,其它参数会从 hippo4j-server 服务拉取。
 
NOTE:创建线程池时建议填充实际的参数。如果在连接 Hippo4j Server 端失败时,会使用填充配置创建线程池。
 
项目中使用上述定义的动态线程池,如下所示:
@Resource
private ThreadPoolExecutor messageConsumeDynamicExecutor;

messageConsumeDynamicExecutor.execute(() -> xxx);

@Resource
private ThreadPoolExecutor messageProduceDynamicExecutor;

messageProduceDynamicExecutor.execute(() -> xxx);
 
 
 

3.5常见

3.5.1、如何server集群?

官方回复不支持集群处理,本地测试:启动两个server(同一个mysql),启动一个client。结论如下:可以在client绑定的server端看到线程池实例,可修改。另一个server端看不到实例,无法操作。
 

3.5.2、搞定tomcat监控,dubbo监控?

Hippo4j 目前已支持的三方框架线程池列表:
  • Dubbo
  • Hystrix
  • RabbitMQ
  • RocketMQ
  • AlibabaDubbo
  • RocketMQSpringCloudStream
  • RabbitMQSpringCloudStream
引入 Hippo4j Server 或 Core 的 Maven Jar 坐标后,还需要引入对应的框架适配 Jar:
<dependency>
    <groupId>cn.hippo4j</groupId>
    <!-- Dubbo -->
    <artifactId>hippo4j-spring-boot-starter-adapter-dubbo</artifactId>
    <!-- Alibaba Dubbo -->
    <artifactId>hippo4j-spring-boot-starter-adapter-alibaba-dubbo</artifactId>
    <!-- Hystrix -->
    <artifactId>hippo4j-spring-boot-starter-adapter-hystrix</artifactId>
    <!-- RabbitMQ -->
    <artifactId>hippo4j-spring-boot-starter-adapter-rabbitmq</artifactId>
    <!-- RocketMQ -->
    <artifactId>hippo4j-spring-boot-starter-adapter-rocketmq</artifactId>
    <!-- SpringCloud Stream RocketMQ -->
    <artifactId>hippo4j-spring-boot-starter-adapter-spring-cloud-stream-rocketmq</artifactId>
    <!-- SpringCloud Stream RabbitMQ -->
    <artifactId>hippo4j-spring-boot-starter-adapter-spring-cloud-stream-rabbitmq</artifactId>
    <version>1.5.0</version>
</dependency>
如果想省事,仅需引入一个全量包,框架底层会根据条件判断加载具体线程池适配器。
<dependency>
    <groupId>cn.hippo4j</groupId>
    <artifactId>hippo4j-spring-boot-starter-adapter-all</artifactId>
    <version>1.5.0</version>
</dependency>
tomcat监控默认自带,可在菜单栏直接观测。dubbo按配置配置后未显示监控详情,用最新版hippo4j尝试,还是没效果,打算上测试环境尝试。
 

3.5.3、server同client端通信机制?是推还是拉?降核心数会如何?会丢弃原先池中的核心数吗?

client -> server 拉,如果拉失败则使用默认参数填充
server -> client 推
经测试:
1、server未启动,client则启动报错,线程池可以使用默认参数创建成功,
2、突然断掉server服务,client报错。[client.scheduled.health.check_0] ERROR c.h.s.s.r.HttpScheduledHealthCheck -Failed to periodically check the health status of the server. message: Connection refused: connect,已创建线程池可以继续使用。
 
缩容原理:不会丢弃任务,任务执行完之后再缩容,不会丢弃原先池中的核心数,示例如下
 

3.5.4、bus改defaultThread

如果client有线程池默认配置了,server端没,会将client配置同步到server。
如果server端有配置,自建线程池也有默认值,则使用server端配置
均可以直接修改连接池参数
 
 
posted @ 2024-06-25 11:54  GL_BKY  阅读(17)  评论(0编辑  收藏  举报