Sentinel 监控数据持久化(mysql)

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;
    }

    @Override
    public 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();

    @Override
    public 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();
        }
    }

    @Override
    public 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();
        }
    }

    @Override
    public 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

修改统计时长修改如下标记处代码: 

2.4.2 MetricFetcher

3. 验证查询数据库

  • 9
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要将Sentinel Dashboard的监控数据持久化MySQL,可以按照以下步骤进行操作: 1. 首先,根据官方文档,对Sentinel Dashboard进行优化,使其支持将监控数据存储到MySQL数据库中。这通常涉及到修改配置文件和引入相应的依赖包。 2. 其次,需要创建一个MySQL数据库,并配置Sentinel Dashboard的连接信息,包括数据库地址、用户名和密码等。这样,Sentinel Dashboard就可以将监控数据存储到MySQL数据库中了。 3. 接下来,可以使用MyBatis-Plus这个工具对MySQL中的监控数据进行操作。MyBatis-Plus是一种优秀的持久层框架,可以方便地进行数据库操作。 4. 通过配置Sentinel规则持久化MySQL,可以实现限流、降级、热点等功能。这可以通过修改项目配置文件中的相关设置来实现。具体的步骤和配置可以参考项目文档或者示例代码。 总结起来,要将Sentinel Dashboard的监控数据持久化MySQL,首先需要对Sentinel Dashboard进行优化以支持MySQL存储,然后创建MySQL数据库并配置连接信息,接着使用MyBatis-Plus对数据进行操作,最后配置Sentinel规则持久化MySQL。这样就可以实现将Sentinel Dashboard的监控数据持久化MySQL的功能了。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Sentinel 控制台实时监控持久化MySQL](https://blog.csdn.net/zhangchaoyang/article/details/124159139)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [sentinel规则(都已实现)持久化mysql数据库,解压修改数据库地址即可使用,里面有数据库需要创建的表sql](https://download.csdn.net/download/zbh1957282580/85561031)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值