可视化管理服务

动态线程池架构模式对比

像动态线程池的架构,在现有市场上通常有两种实现方式:

  • 一种是基于 配置中心,整体较为轻量,接入简单,但扩展性不足,个性化更新和功能拓展受限,所有操作都依赖配置中心
  • 另一种是不依赖中间件而是 单独部署独立服务与业务交互,功能更丰富、可视化更友好,但需要 额外运维一套中间件,稳定性和运维成本相对更高

抽象 Nacos API 操作

1. 核心方法设计

NacosProxyClient 包含四个核心方法,可以参考 Nacos Open API 指南

  • listConfig方法 :查询命名空间下 配置文件集合

  • getConfig方法 :查询 配置明细信息

  • publishConfig方法 :发布配置

  • service方法 :查询 服务明细

2. 参数处理与命名空间隔离

NacosProxyClient 在处理参数时,特别注意了命名空间的隔离问题。在 Nacos 中,命名空间是用于区分不同环境(如开发、测试、生产)的隔离单元。通过判断namespace是否为"public"NacosProxyClient能够正确处理不同命名空间下的配置请求

1
2
3
4
5
// 在listConfig方法中
form("tenant", Objects.equals(namespace, "public") ? "" : namespace)

// 在 service方法中
form("namespaceId", Objects.equals(namespace, "public") ? "" : namespace)

配置文件如是写到

1
2
3
4
5
6
namespaces: # 需要从 Nacos 中读取以下命名空间(自定义)配置文件检索动态线程池
- public
- framework
- common
- test
- prod

3. YAML 配置解析与绑定

NacosProxyClient 在查询配置后,需要将配置内容解析为 Java 对象

DashBoard-Dev 服务的功能与实现机制

真正的核心在于 线程池管理Web线程池管理

线程池管理和实例有什么区别?

线程池管理控制层

提供两个函数:查询线程池集合更新线程池

  • 查询线程池集合:如果前端传了 namespace,就只查这一个;否则(public 的情况)查所有配置的 namespace
  • 更新线程池:全局配置,并调用 Nacos 发布接口持久化到Nacos

针对全局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class ThreadPoolManagerController {
private final ThreadPoolManagerService threadPoolManagerService;
/**
* 查询线程池集合
* 如果前端传了 namespace,就只查这一个;否则查所有配置的 namespace
*/
@GetMapping("/api/ysythread-dashboard/thread-pools")
public Result<List<ThreadPoolDetailRespDTO>> listThreadPool(ThreadPoolListReqDTO requestParam) {
return Results.success(threadPoolManagerService.listThreadPool(requestParam));
}
/**
* 更新线程池(全局配置)
*/
@PutMapping("/api/ysythread-dashboard/thread-pool")
public Result<Void> updateGlobalThreadPool(@RequestBody @Valid ThreadPoolUpdateReqDTO requestParam) {
threadPoolManagerService.updateGlobalThreadPool(requestParam);
return Results.success();
}
}

线程池实例控制层

提供两个函数:获取动态线程池列表获取动态线程池的完整运行时状态(即获取列表与状态)

  • 获取动态线程池列表 :获取 某个服务下,指定线程池在 所有实例中的基础指标
  • 获取动态线程池的完整运行时状态:获取 指定实例 上,某个线程池 的详细运行时状态
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class ThreadPoolInstanceController {
private final ThreadPoolInstanceService threadPoolInstanceService;
/**
* 获取动态线程池列表
*/
@GetMapping("/api/ysythread-dashboard/thread-pools/{namespace}/{serviceName}/{threadPoolId}/basic-metrics")
public Result<List<ThreadPoolBaseMetricsRespDTO>> listBasicMetrics(
@PathVariable String namespace,
@PathVariable String serviceName,
@PathVariable String threadPoolId) {
return Results.success(threadPoolInstanceService.listBasicMetrics(namespace, serviceName, threadPoolId));
}
/**
* 获取动态线程池的完整运行时状态
*/
@GetMapping("/api/ysythread-dashboard/thread-pool/{threadPoolId}/{networkAddress}")
public Result<ThreadPoolStateRespDTO> getRuntimeState(
@PathVariable String threadPoolId,
@PathVariable String networkAddress) {
return Results.success(threadPoolInstanceService.getRuntimeState(threadPoolId, networkAddress));
}
}

实例层是如何获取运行时状态?

dashboard-dev中的 实例层函数 通过DashBoard Starter 提供的内置接口!操作如下

1
2
3
4
// 调用 DashBoard Starter 提供的内置接口,获取线程池运行信息
String networkAddress = service.getIp() + ":" + service.getPort();
// 假设目标微服务集成了动态线程池 Starter,它会暴露 http://endpoint/dynamic/thread-pool/{id}/basic-metrics
String resultStr = HttpUtil.get("http://" + networkAddress + "/dynamic/thread-pool/" + threadPoolId + "/basic-metrics");

dashboard-dev 与 starter 的关系与作用

1
2
3
4
.
├── dashboard-dev # 前端页面方便查看和调试
└── starter # 动态线程池配置中心组件包,实现线程池结合Spring框架和配置中心动态刷新
  ├── dashboard-dev-spring-boot-starter # 控制台 API 组件库

dashboard-dev 的作用

  1. 给前端 提供接口,比如重要的几个(Nacos查询与更新

  2. 让用户可以直接在前端页面上 修改配置,而不用通过Nacos发布配置

dashboard-…-starter 的作用

  1. 提供线程池监控能力,暴露了标准的 Web 接口,让dashboard-dev可以获取线程池的运行信息

  2. 控制器中提供了两类接口:

    1. 轻量级 指标接口】用于线程池列表展示,快速获取 基础运行信息
    2. 完整 运行时接口】用于 详情页面,展示线程池的全面状态

控制层暴露的两个接口,方便dashboard-dev直接调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class DynamicThreadPoolController {
private final DynamicThreadPoolService dynamicThreadPoolService;
/**
* 获取线程池的轻量级运行指标
*/
@GetMapping("/dynamic/thread-pool/{threadPoolId}/basic-metrics")
public Result<ThreadPoolDashBoardDevBaseMetricsRespDTO> getBasicMetrics(@PathVariable String threadPoolId) {
return Results.success(dynamicThreadPoolService.getBasicMetrics(threadPoolId));
}
/**
* 获取线程池的完整运行时状态
*/
@GetMapping("/dynamic/thread-pool/{threadPoolId}")
public Result<ThreadPoolDashBoardDevRespDTO> getRuntimeInfo(@PathVariable String threadPoolId) {
return Results.success(dynamicThreadPoolService.getRuntimeInfo(threadPoolId));
}
}

总结

用到一种很巧妙的方法,dashboard-starter中的控制层暴露获取线程池运行时的指标,dashboard-dev服务调用dashboard-starter暴露的接口来实现前端需要的动态查询操作!