Sentinel 实时监控仅存储 5 分钟以内的数据,如果需要持久化,需要通过调用实时监控接口来定制,即自行扩展实现 MetricsRepository 接口(修改 控制台源码)。
本文通过使用Mysql持久化监控数据。
1.构建存储表(mysql)
CREATE TABLE `sentinel_metric` (`id` INT NOT NULL AUTO_INCREMENT COMMENT 'id,主键',`gmt_create` DATETIME COMMENT '创建时间',`gmt_modified` DATETIME COMMENT '修改时间',`app` VARCHAR(100) COMMENT '应用名称',`timestamp` DATETIME COMMENT '统计时间',`resource` VARCHAR(500) COMMENT '资源名称',`pass_qps` INT COMMENT '通过qps',`success_qps` INT COMMENT '成功qps',`block_qps` INT COMMENT '限流qps:拒绝的qps',`exception_qps` INT COMMENT '发送异常的次数',`rt` DOUBLE COMMENT '所有successQps的rt的和,单位ms; 控制台响应时间(平均响应时间)=rt/success_qps',`count` INT COMMENT '本次聚合的总条数: 集群的服务数量',`resource_code` INT COMMENT '资源的hashCode',INDEX app_idx(`app`) USING BTREE,INDEX timestamp_idx(`timestamp`) USING BTREE,PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
2.修改控制台源码
2.1 添加Maven依赖
<!-- mysql db --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.25</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version></dependency>
2.2 修改配置文件
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xx?useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=xx
spring.datasource.password=xxxxx
spring.datasource.driver-class=com.mysql.cj.jdbc.Driver
2.3 逆向代码生成(新增)
参考:Springboot入门之Mybatis逆向工程_Ocean@上源码的博客-CSDN博客
package com.alibaba.csp.sentinel.dashboard.metric.dao;import com.alibaba.csp.sentinel.dashboard.datasource.entity.MetricEntity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;import java.util.Date;@TableName("sentinel_metric")
public class Metric {/*** 主键ID*/@TableId(value = "id", type = IdType.INPUT)private Long id;/*** 创建时间*/@TableField("gmt_create")private Date gmtCreate;/*** 修改时间*/@TableField("gmt_modified")private Date gmtModified;/*** 应用名称*/private String app;/*** 监控信息的时间戳*/private Date timestamp;/*** 资源名*/private String resource;/*** 通过qps*/@TableField("pass_qps")private Long passQps;/*** 成功qps*/@TableField("success_qps")private Long successQps;/*** 限流qps*/@TableField("block_qps")private Long blockQps;/*** 异常qps*/@TableField("exception_qps")private Long exceptionQps;/*** 所有successQps的rt的和*/private Double rt;/*** 本次聚合的总条数*/private Integer count;/*** 资源的hashCode*/@TableField("resource_code")private Integer resourceCode;public Metric(MetricEntity metric) {this.id = metric.getId();this.gmtCreate = metric.getGmtCreate();this.gmtModified = metric.getGmtModified();this.app = metric.getApp();this.timestamp = metric.getTimestamp();this.resource = metric.getResource();this.passQps = metric.getPassQps();this.successQps = metric.getSuccessQps();this.blockQps = metric.getBlockQps();this.exceptionQps = metric.getExceptionQps();this.rt = metric.getRt();this.count = metric.getCount();this.resourceCode = metric.getResourceCode();}public Metric() {}public Long getId() {return id;}public void setId(Long id) {this.id = id;}public Date getGmtCreate() {return gmtCreate;}public void setGmtCreate(Date gmtCreate) {this.gmtCreate = gmtCreate;}public Date getGmtModified() {return gmtModified;}public void setGmtModified(Date gmtModified) {this.gmtModified = gmtModified;}public String getApp() {return app;}public void setApp(String app) {this.app = app;}public Date getTimestamp() {return timestamp;}public void setTimestamp(Date timestamp) {this.timestamp = timestamp;}public String getResource() {return resource;}public void setResource(String resource) {this.resource = resource;}public Long getPassQps() {return passQps;}public void setPassQps(Long passQps) {this.passQps = passQps;}public Long getSuccessQps() {return successQps;}public void setSuccessQps(Long successQps) {this.successQps = successQps;}public Long getBlockQps() {return blockQps;}public void setBlockQps(Long blockQps) {this.blockQps = blockQps;}public Long getExceptionQps() {return exceptionQps;}public void setExceptionQps(Long exceptionQps) {this.exceptionQps = exceptionQps;}public Double getRt() {return rt;}public void setRt(Double rt) {this.rt = rt;}public Integer getCount() {return count;}public void setCount(Integer count) {this.count = count;}public Integer getResourceCode() {return resourceCode;}public void setResourceCode(Integer resourceCode) {this.resourceCode = resourceCode;}@Overridepublic String toString() {return "SentinelMetricsEntity{" +"id=" + id +", gmtCreate=" + gmtCreate +", gmtModified=" + gmtModified +", app='" + app + '\'' +", timestamp=" + timestamp +", resource='" + resource + '\'' +", passQps=" + passQps +", successQps=" + successQps +", blockQps=" + blockQps +", exceptionQps=" + exceptionQps +", rt=" + rt +", count=" + count +", resourceCode=" + resourceCode +'}';}}
package com.alibaba.csp.sentinel.dashboard.metric.dao;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface MetricMapper extends BaseMapper<Metric> {}
package com.alibaba.csp.sentinel.dashboard.metric.service;import com.alibaba.csp.sentinel.dashboard.datasource.entity.MetricEntity;
import com.alibaba.csp.sentinel.dashboard.metric.dao.Metric;
import com.baomidou.mybatisplus.extension.service.IService;import java.util.Collection;
import java.util.List;/*** <p>* 服务类* </p>** @author ocean* @since 2023-05-21*/
public interface MetricService extends IService<Metric> {List<String> listResourcesOfApp(String app);List<MetricEntity> queryByAppAndResourceBetween(String app, String resource, Long startTime, Long endTime);void saveAll(Iterable<MetricEntity> metrics);}
package com.alibaba.csp.sentinel.dashboard.metric.service.impl;import com.alibaba.csp.sentinel.dashboard.datasource.entity.MetricEntity;
import com.alibaba.csp.sentinel.dashboard.metric.dao.Metric;
import com.alibaba.csp.sentinel.dashboard.metric.dao.MetricMapper;
import com.alibaba.csp.sentinel.dashboard.metric.service.MetricService;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.Collectors;@Service
public class MetricServiceImpl extends ServiceImpl<MetricMapper, Metric> implements MetricService {private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();@Overridepublic void saveAll(Iterable<MetricEntity> metrics) {if (metrics == null) {return;}readWriteLock.writeLock().lock();try {List<Metric> metricList = Lists.newArrayList();metrics.forEach(data -> {metricList.add(new Metric(data));});this.saveBatch(metricList);} finally {readWriteLock.writeLock().unlock();}}@Overridepublic List<String> listResourcesOfApp(String app) {List<String> results = new ArrayList<>();if (StringUtil.isBlank(app)) {return results;}readWriteLock.readLock().lock();try {LambdaQueryWrapper<Metric> metricLambdaQueryWrapper = Wrappers.lambdaQuery(Metric.class).eq(Metric::getApp, app).orderByAsc(Metric::getTimestamp);return this.list(metricLambdaQueryWrapper).stream().map(Metric::getResource).collect(Collectors.toList());} finally {readWriteLock.readLock().unlock();}}@Overridepublic List<MetricEntity> queryByAppAndResourceBetween(String app, String resource, Long startTime, Long endTime) {List<MetricEntity> results = new ArrayList<>();if (StringUtil.isBlank(app)) {return results;}readWriteLock.readLock().lock();try {LambdaQueryWrapper<Metric> metricLambdaQueryWrapper = Wrappers.lambdaQuery(Metric.class).eq(Metric::getApp, app).eq(Metric::getResource, resource).ge(Metric::getTimestamp, new Date(startTime)).le(Metric::getTimestamp, new Date(endTime)).orderByAsc(Metric::getTimestamp);List<Metric> metricList = this.list(metricLambdaQueryWrapper);return metricList.stream().map(MetricEntity::new).collect(Collectors.toList());} finally {readWriteLock.readLock().unlock();}}
}
2.4 修改源码
2.4.1 MetricController
修改统计时长修改如下标记处代码: