目录

chen 的个人博客

VX:ZzzChChen
Phone:13403656751
Email:zxydczzs@gmail.com

X

Hippo4j 动态线程池监控优化改造

一、本次优化点

  1. 「线程池监控」查询范围由原先的 30 分钟改为 60 分钟且可配置化;
  2. 「线程池监控」增加时间选择器,可选范围 10 天;
  3. 「线程池监控」数据库数据持久化 10 天且可配置;

二、优化步骤

前端部分:增加时间选择器组件、设置默认时间、中英文转译、传递至后端

  1. 修改页面路径:/hippo4j-ui/src/views/hippo4j/monitor/index.vue,在 class 为「filter-container」的大块后面接着写

    1    <div>
    2      <el-date-picker v-model="listQuery.entTime" type="datetime" placeholder="请选择截止时间" :picker-options="pickerOptions">
    3      </el-date-picker>
    4    </div>
    
  2. 选择地址及端口的选择器代码修改

    1      <el-select v-model="listQuery.identify" :placeholder="$t('threadPoolMonitor.ipPortRequired')" style="width: 220px"
    2        filterable class="filter-item" @change="identifyChange">
    3        <el-option v-for="item in identifyOptions" :key="item.key" :label="item.display_name" :value="item.key" />
    4      </el-select>
    
  3. 「data」块更改

     1  data() {
     2    return {
     3      pickerOptions: {
     4        disabledDate(time) {
     5          let curDateMillisecond = (new Date()).getTime();
     6          let tenDaysMillisecond = 10 * 24 * 3600 * 1000;
     7          let tenDaysTime = curDateMillisecond - tenDaysMillisecond;
     8          return time.getTime() > Date.now() || time.getTime() < tenDaysTime;;
     9        }
    10      },
    11      listQuery: {
    12        endTime: null
    13      },
    14      endTime: null
    15    };
    16  }
    
  4. 「methods」方法更改

     1    identifyChange(identify) {
     2      if (identify) {
     3        this.endTime = new Date();
     4      }
     5    },
     6    fetchData() {
     7      if (!this.listQuery.tenantId) {
     8        this.$message.warning(this.$t('message.emptyWarning', { name: this.$t('tenantManage.tenant') }));
     9        return;
    10      }
    11      if (!this.listQuery.itemId) {
    12        this.$message.warning(this.$t('message.emptyWarning', { name: this.$t('projectManage.item') }));
    13        return;
    14      }
    15      if (!this.listQuery.tpId) {
    16        this.$message.warning(this.$t('message.emptyWarning', { name: this.$t('threadPool.threadPool') }));
    17        return;
    18      }
    19      if (!this.listQuery.identify) {
    20        this.$message.warning(this.$t('message.emptyWarning', { name: this.$t('threadPoolMonitor.ipPort') }));
    21        return;
    22      }
    23      if (this.endTime) {
    24        let time = this.endTime;
    25        time.setHours(time.getHours() + 8);
    26        this.listQuery.endTime = time.toISOString();
    27        time.setHours(time.getHours() - 8);
    28      }
    29      this.listQuery.instanceId = this.listQuery.identify;
    30      threadPoolApi.info(this.listQuery).then((res) => {
    31        this.temp = res;
    32      });
    33
    34      // monitorApi.lastTaskCountFun(this.listQuery).then((res) => {
    35      //   this.rejectCount = res.rejectCount;
    36      //   this.lastTaskCount = res.completedTaskCount;
    37      // });
    38
    39      this.initChart();
    40    },
    41    refreshData() {
    42      this.listQuery.tenantId = null;
    43      this.listQuery.itemId = null;
    44      this.listQuery.tpId = null;
    45      this.listQuery.identify = null;
    46      this.itemOptions = [];
    47      this.threadPoolOptions = [];
    48      this.identifyOptions = [];
    49      this.listQuery.endTime = null;
    50      this.endTime = null;
    51    }
    
  5. 中英文转译,js 路径 /hippo4j-ui/src/locale/lang/zh.js、/hippo4j-ui/src/locale/lang/en.js,分别在 js 页面下找到如下代码块,增加 chooseDeadline 以及对应翻译

     1  //线程池监控
     2  threadPoolMonitor: {
     3    ipPort: 'IP : Port',
     4    ipPortRequired: 'IP : Port(必填)',
     5    noResultsYet: '暂无结果',
     6    chooseDeadline: '请选择截止时间',
     7  },
     8
     9  //线程池监控
    10  threadPoolMonitor: {
    11    ipPort: 'IP : Port',
    12    ipPortRequired: 'IP : Port(Required)',
    13    noResultsYet: 'No results yet',
    14    chooseDeadline: 'Choose deadline',
    15  },
    
  6. 编译前端项目,执行「package.json」中 scritps 的第二个命令 vue-cli-service build,会生成或重新替换 dist 目录下的文件,将该目录下的所有文件替换 /hippo4j//hippo4j-server/hippo4j-console/src/main/resources/static 该目录下的静态文件,前端即完成;也可单独将前端代码拉出来部署,后端不依赖静态文件,需要改动前端访问后端接口的 ip+port,在 vue.config.js 中 查找 http://127.0.0.1:6691/hippo4j/v1/cs 后替换即可;

后端部分:接口动态查询,数据持久化配置、查询范围配置

  1. 我这边是将原本的内置配置文件,改为了读取 nacos 中的配置文件,有个一层注册中心的概念,大家可参考下;

  2. 在 hippo4j-config 的 pom.xml 中引入如下依赖

    1        <dependency>
    2            <groupId>org.springframework.cloud</groupId>
    3            <artifactId>spring-cloud-starter-bootstrap</artifactId>
    4            <version>3.0.2</version>
    5        </dependency>
    
  3. 修改 ServerBootstrapProperties

     1/*
     2 * Licensed to the Apache Software Foundation (ASF) under one or more
     3 * contributor license agreements.  See the NOTICE file distributed with
     4 * this work for additional information regarding copyright ownership.
     5 * The ASF licenses this file to You under the Apache License, Version 2.0
     6 * (the "License"); you may not use this file except in compliance with
     7 * the License.  You may obtain a copy of the License at
     8 *
     9 *     http://www.apache.org/licenses/LICENSE-2.0
    10 *
    11 * Unless required by applicable law or agreed to in writing, software
    12 * distributed under the License is distributed on an "AS IS" BASIS,
    13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14 * See the License for the specific language governing permissions and
    15 * limitations under the License.
    16 */
    17
    18package cn.hippo4j.config.config;
    19
    20import lombok.Getter;
    21import lombok.Setter;
    22import lombok.extern.slf4j.Slf4j;
    23import org.springframework.boot.context.properties.ConfigurationProperties;
    24import org.springframework.cloud.context.config.annotation.RefreshScope;
    25import org.springframework.context.annotation.Configuration;
    26
    27/**
    28 * Server bootstrap properties.
    29 */
    30@Slf4j
    31@Getter
    32@Setter
    33@RefreshScope
    34@Configuration
    35@ConfigurationProperties(prefix = ServerBootstrapProperties.PREFIX)
    36public class ServerBootstrapProperties {
    37
    38    public final static String PREFIX = "hippo4j.core";
    39
    40    /**
    41     * Whether to start the background task of cleaning up thread pool history data.
    42     */
    43    private Boolean cleanHistoryDataEnable = Boolean.TRUE;
    44
    45    /**
    46     * Regularly clean up the historical running data of thread pool. unit: minute.
    47     */
    48    private Integer cleanHistoryDataPeriod = 30;
    49
    50    /**
    51     * query up the historical running data of thread pool. unit: minute.
    52     */
    53    private Integer queryHistoryDataPeriod = 60;
    54
    55    /**
    56     * Netty server port.
    57     */
    58    private String nettyServerPort = "8899";
    59}
    60
    
  4. 修改 MonitorQueryReqDTO

     1/*
     2 * Licensed to the Apache Software Foundation (ASF) under one or more
     3 * contributor license agreements.  See the NOTICE file distributed with
     4 * this work for additional information regarding copyright ownership.
     5 * The ASF licenses this file to You under the Apache License, Version 2.0
     6 * (the "License"); you may not use this file except in compliance with
     7 * the License.  You may obtain a copy of the License at
     8 *
     9 *     http://www.apache.org/licenses/LICENSE-2.0
    10 *
    11 * Unless required by applicable law or agreed to in writing, software
    12 * distributed under the License is distributed on an "AS IS" BASIS,
    13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14 * See the License for the specific language governing permissions and
    15 * limitations under the License.
    16 */
    17
    18package cn.hippo4j.config.model.biz.monitor;
    19
    20import lombok.Data;
    21
    22import java.time.LocalDateTime;
    23
    24/**
    25 * Monitor query req DTO.
    26 */
    27@Data
    28public class MonitorQueryReqDTO {
    29
    30    /**
    31     * Tenant id
    32     */
    33    private String tenantId;
    34
    35    /**
    36     * Item id
    37     */
    38    private String itemId;
    39
    40    /**
    41     * Thread-pool id
    42     */
    43    private String tpId;
    44
    45    /**
    46     * Instance id
    47     */
    48    private String instanceId;
    49
    50    /**
    51     * end time
    52     * 截止时间
    53     */
    54    private LocalDateTime endTime;
    55}
    56
    
  5. 修改 HisRunDataServiceImpl 类下的 queryqueryInfoThreadPoolMonitorqueryThreadPoolLastTaskCount 方法

     1    @Override
     2    public List<MonitorRespDTO> query(MonitorQueryReqDTO reqDTO) {
     3        LocalDateTime currentDate = LocalDateTime.now();
     4        LocalDateTime dateTime = currentDate.plusMinutes(-properties.getQueryHistoryDataPeriod());
     5        long startTime = DateUtil.getTime(dateTime);
     6        List<HisRunDataInfo> hisRunDataInfos = this.lambdaQuery()
     7                .eq(HisRunDataInfo::getTenantId, reqDTO.getTenantId())
     8                .eq(HisRunDataInfo::getItemId, reqDTO.getItemId())
     9                .eq(HisRunDataInfo::getTpId, reqDTO.getTpId())
    10                .eq(HisRunDataInfo::getInstanceId, reqDTO.getInstanceId())
    11                .between(HisRunDataInfo::getTimestamp, startTime, DateUtil.getTime(currentDate))
    12                .orderByAsc(HisRunDataInfo::getTimestamp)
    13                .list();
    14        return BeanUtil.convert(hisRunDataInfos, MonitorRespDTO.class);
    15    }
    16
    17    @Override
    18    public MonitorActiveRespDTO queryInfoThreadPoolMonitor(MonitorQueryReqDTO reqDTO) {
    19        LocalDateTime currentDate;
    20        if (Objects.isNull(reqDTO.getEndTime())) {
    21            currentDate = LocalDateTime.now();
    22        } else {
    23            currentDate = reqDTO.getEndTime();
    24        }
    25        LocalDateTime dateTime = currentDate.plusMinutes(-properties.getQueryHistoryDataPeriod());
    26        long startTime = DateUtil.getTime(dateTime);
    27        List<HisRunDataInfo> hisRunDataInfos = this.lambdaQuery()
    28                .eq(HisRunDataInfo::getTenantId, reqDTO.getTenantId())
    29                .eq(HisRunDataInfo::getItemId, reqDTO.getItemId())
    30                .eq(HisRunDataInfo::getTpId, reqDTO.getTpId())
    31                .eq(HisRunDataInfo::getInstanceId, reqDTO.getInstanceId())
    32                .between(HisRunDataInfo::getTimestamp, startTime, DateUtil.getTime(currentDate))
    33                .orderByAsc(HisRunDataInfo::getTimestamp)
    34                .list();
    35        List<String> times = new ArrayList<>();
    36        List<Long> poolSizeList = new ArrayList<>();
    37        List<Long> activeSizeList = new ArrayList<>();
    38        List<Long> queueCapacityList = new ArrayList<>();
    39        List<Long> queueSizeList = new ArrayList<>();
    40        List<Long> completedTaskCountList = new ArrayList<>();
    41        List<Long> rejectCountList = new ArrayList<>();
    42        List<Long> queueRemainingCapacityList = new ArrayList<>();
    43        List<Long> currentLoadList = new ArrayList<>();
    44        long countTemp = 0L;
    45        AtomicBoolean firstFlag = new AtomicBoolean(Boolean.TRUE);
    46        for (HisRunDataInfo each : hisRunDataInfos) {
    47            String time = DateUtil.format(new Date(each.getTimestamp()), NORM_TIME_PATTERN);
    48            times.add(time);
    49            poolSizeList.add(each.getPoolSize());
    50            activeSizeList.add(each.getActiveSize());
    51            queueSizeList.add(each.getQueueSize());
    52            rejectCountList.add(each.getRejectCount());
    53            queueRemainingCapacityList.add(each.getQueueRemainingCapacity());
    54            currentLoadList.add(each.getCurrentLoad());
    55            queueCapacityList.add(each.getQueueCapacity());
    56            if (firstFlag.get()) {
    57                completedTaskCountList.add(0L);
    58                firstFlag.set(Boolean.FALSE);
    59                countTemp = each.getCompletedTaskCount();
    60                continue;
    61            }
    62            long completedTaskCount = each.getCompletedTaskCount();
    63            long countTask = completedTaskCount - countTemp;
    64            completedTaskCountList.add(countTask);
    65            countTemp = each.getCompletedTaskCount();
    66        }
    67        return new MonitorActiveRespDTO(times, poolSizeList, activeSizeList, queueSizeList, completedTaskCountList, rejectCountList, queueRemainingCapacityList, currentLoadList, queueCapacityList);
    68    }
    69
    70    @Override
    71    public MonitorRespDTO queryThreadPoolLastTaskCount(MonitorQueryReqDTO reqDTO) {
    72        LocalDateTime currentDate = LocalDateTime.now();
    73        LocalDateTime dateTime = currentDate.plusMinutes(-properties.getQueryHistoryDataPeriod());
    74        long startTime = DateUtil.getTime(dateTime);
    75        HisRunDataInfo hisRunDataInfo = this.lambdaQuery()
    76                .eq(HisRunDataInfo::getTenantId, reqDTO.getTenantId())
    77                .eq(HisRunDataInfo::getItemId, reqDTO.getItemId())
    78                .eq(HisRunDataInfo::getTpId, reqDTO.getTpId())
    79                .eq(HisRunDataInfo::getInstanceId, reqDTO.getInstanceId())
    80                .orderByDesc(HisRunDataInfo::getTimestamp)
    81                .between(HisRunDataInfo::getTimestamp, startTime, DateUtil.getTime(currentDate))
    82                .last("LIMIT 1")
    83                .one();
    84        return BeanUtil.convert(hisRunDataInfo, MonitorRespDTO.class);
    85    }
    
  6. 在 nacos 中可以自定义查询时间以及数据持久化时间配置,由于加了 @RefreshScope 注解,修改后会立即生效

    1# 是否开启线程池历史数据清洗 false 不开启
    2hippo4j:
    3  core:
    4    clean-history-data-enable: true
    5    clean-history-data-period: 14400
    6    query-history-data-period: 60
    

三、注意事项

  1. 客户端在每次启动时,都会根据一些信息动态的生成实例标识,这也是查询线程池监控数据的查询参数,这就导致了,本次启动后会查询不到之前的线程池监控数据;

标题:Hippo4j 动态线程池监控优化改造
作者:zzzzchen
地址:https://dczzs.com/articles/2023/07/25/1690276490935.html