sentinel 官方文档_Sentinel控制台监控数据持久化到MySQL数据库

根据官方wiki文档,Sentinel控制台的实时监控数据,默认仅存储 5 分钟以内的数据。如需持久化,需要定制实现相关接口。

https://github.com/alibaba/Sentinel/wiki/在生产环境中使用-Sentinel

1eaeb407b23a410053ad8b880d9d5461.png

给出了指导步骤:

  • 自行扩展实现 MetricsRepository 接口;
  • 注册成 Spring Bean 并在相应位置通过 @Qualifier 注解指定对应的 bean name 即可;

0x01:MetricsRepository接口定义

package com.alibaba.csp.sentinel.dashboard.repository.metric;import java.util.List;public interface MetricsRepository {    void save(T metric);    void saveAll(Iterable metrics);    List queryByAppAndResourceBetween(String app, String resource, long startTime, long endTime);    List listResourcesOfApp(String app);}

该接口就只定义4个方法,分别用于保存和查询Sentinel的metric数据。注释其实很清楚了,解析如下:

  • save:保存单个metric
  • saveAll:保存多个metric
  • queryByAppAndResourceBetween:通过应用名称、资源名称、开始时间、结束时间查询metric列表
  • listResourcesOfApp:通过应用名称查询资源列表

目前该接口只有一个基于内存级别的实现类:com.alibaba.csp.sentinel.dashboard.repository.metric.InMemoryMetricsRepository。

另外还有一个实体类com.alibaba.csp.sentinel.dashboard.datasource.entity.MetricEntity,如下图

c80c3e1d4a6cfae16187ab39e32d7828.png

梳理了相关的类关系就可以实现了。

0x02:根据MetricEntity新建数据库和新建实体类

建表语句如下

-- 创建监控数据表CREATE TABLE `t_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',  `exception_qps` INT COMMENT '发送异常的次数',  `rt` DOUBLE COMMENT '所有successQps的rt的和',  `_count` INT COMMENT '本次聚合的总条数',  `resource_code` INT COMMENT '资源的hashCode',  INDEX app_idx(`app`) USING BTREE,  INDEX resource_idx(`resource`) USING BTREE,  INDEX timestamp_idx(`timestamp`) USING BTREE,  PRIMARY KEY (`id`)) ENGINE=INNODB DEFAULT CHARSET=utf8;

实体类如下

package com.alibaba.csp.sentinel.dashboard.datasource.entity;import javax.persistence.*;import java.io.Serializable;import java.util.Date;/** * @author 2230 * */@Entity@Table(name = "t_sentinel_metric")public class MetricDto implements Serializable {    private static final long serialVersionUID = 7200023615444172715L;    /**id,主键*/    @Id    @GeneratedValue    @Column(name = "id")    private Long id;    /**创建时间*/    @Column(name = "gmt_create")    private Date gmtCreate;    /**修改时间*/    @Column(name = "gmt_modified")    private Date gmtModified;    /**应用名称*/    @Column(name = "app")    private String app;    /**统计时间*/    @Column(name = "timestamp")    private Date timestamp;    /**资源名称*/    @Column(name = "resource")    private String resource;    /**通过qps*/    @Column(name = "pass_qps")    private Long passQps;    /**成功qps*/    @Column(name = "success_qps")    private Long successQps;    /**限流qps*/    @Column(name = "block_qps")    private Long blockQps;    /**发送异常的次数*/    @Column(name = "exception_qps")    private Long exceptionQps;    /**所有successQps的rt的和*/    @Column(name = "rt")    private Double rt;    /**本次聚合的总条数*/    @Column(name = "_count")    private Integer count;    /**资源的hashCode*/    @Column(name = "resource_code")    private Integer resourceCode;   // get  set 方法省略}

0x03:pom.xml添加依赖

因为是基于JPA和MySQL数据库实现,所以需要添加JPA依赖和MySQL数据库驱动依赖

             org.springframework.boot          spring-boot-starter-data-jpa          ${spring.boot.version}                            mysql            mysql-connector-java            5.1.47        

0x04:实现MetricsRepository 接口,把数据持久化到MySQL数据库

注意实现添加@Repository("jpaMetricsRepository")配置

package com.alibaba.csp.sentinel.dashboard.repository.metric;import java.time.Instant;import java.util.ArrayList;import java.util.Date;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.stream.Collectors;import javax.persistence.EntityManager;import javax.persistence.PersistenceContext;import javax.persistence.Query;import org.springframework.beans.BeanUtils;import org.springframework.stereotype.Repository;import org.springframework.transaction.annotation.Transactional;import org.springframework.util.CollectionUtils;import com.alibaba.csp.sentinel.dashboard.datasource.entity.MetricDto;import com.alibaba.csp.sentinel.dashboard.datasource.entity.MetricEntity;import com.alibaba.csp.sentinel.util.StringUtil;/** * https://www.cnblogs.com/yinjihuan/p/10574998.html * https://www.cnblogs.com/cdfive2018/p/9838577.html * https://blog.csdn.net/wk52525/article/details/104587239/ * https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel *  * @author 2230 * */@Transactional@Repository("jpaMetricsRepository")public class JpaMetricsRepository implements MetricsRepository {    @PersistenceContext    private EntityManager em;    @Override    public void save(MetricEntity metric) {        if (metric == null || StringUtil.isBlank(metric.getApp())) {            return;        }        MetricDto metricDto = new MetricDto();        BeanUtils.copyProperties(metric, metricDto);        em.persist(metricDto);    }    @Override    public void saveAll(Iterable metrics) {        if (metrics == null) {            return;        }        metrics.forEach(this::save);    }    @Override    public List queryByAppAndResourceBetween(String app, String resource, long startTime, long endTime) {        List results = new ArrayList();        if (StringUtil.isBlank(app)) {            return results;        }        if (StringUtil.isBlank(resource)) {            return results;        }        StringBuilder hql = new StringBuilder();        hql.append("FROM MetricDto");        hql.append(" WHERE app=:app");        hql.append(" AND resource=:resource");        hql.append(" AND timestamp>=:startTime");        hql.append(" AND timestamp<=:endTime");        Query query = em.createQuery(hql.toString());        query.setParameter("app", app);        query.setParameter("resource", resource);        query.setParameter("startTime", Date.from(Instant.ofEpochMilli(startTime)));        query.setParameter("endTime", Date.from(Instant.ofEpochMilli(endTime)));        List metricDtos = query.getResultList();        if (CollectionUtils.isEmpty(metricDtos)) {            return results;        }        for (MetricDto metricDto : metricDtos) {            MetricEntity metricEntity = new MetricEntity();            BeanUtils.copyProperties(metricDto, metricEntity);            results.add(metricEntity);        }        return results;    }    @Override    public List listResourcesOfApp(String app) {        List results = new ArrayList<>();        if (StringUtil.isBlank(app)) {            return results;        }        StringBuilder hql = new StringBuilder();        hql.append("FROM MetricDto");        hql.append(" WHERE app=:app");        hql.append(" AND timestamp>=:startTime");        long startTime = System.currentTimeMillis() - 1000 * 60;        Query query = em.createQuery(hql.toString());        query.setParameter("app", app);        query.setParameter("startTime", Date.from(Instant.ofEpochMilli(startTime)));        List metricDtos = query.getResultList();        if (CollectionUtils.isEmpty(metricDtos)) {            return results;        }        List metricEntities = new ArrayList();        for (MetricDto metricDto : metricDtos) {            MetricEntity metricEntity = new MetricEntity();            BeanUtils.copyProperties(metricDto, metricEntity);            metricEntities.add(metricEntity);        }        Map resourceCount = new HashMap<>(32);        for (MetricEntity metricEntity : metricEntities) {            String resource = metricEntity.getResource();            if (resourceCount.containsKey(resource)) {                MetricEntity oldEntity = resourceCount.get(resource);                oldEntity.addPassQps(metricEntity.getPassQps());                oldEntity.addRtAndSuccessQps(metricEntity.getRt(), metricEntity.getSuccessQps());                oldEntity.addBlockQps(metricEntity.getBlockQps());                oldEntity.addExceptionQps(metricEntity.getExceptionQps());                oldEntity.addCount(1);            } else {                resourceCount.put(resource, MetricEntity.copyOf(metricEntity));            }        }        // Order by last minute b_qps DESC.        return resourceCount.entrySet()                .stream()                .sorted((o1, o2) -> {                    MetricEntity e1 = o1.getValue();                    MetricEntity e2 = o2.getValue();                    int t = e2.getBlockQps().compareTo(e1.getBlockQps());                    if (t != 0) {                        return t;                    }                    return e2.getPassQps().compareTo(e1.getPassQps());                })                .map(Map.Entry::getKey)                .collect(Collectors.toList());    }}

0x05:application.properties配置文件添加数据库配置

# datasourcespring.datasource.driver-class-name=com.mysql.jdbc.Driverspring.datasource.url=jdbc:mysql://127.0.0.1:3306/gateway_v2?characterEncoding=utf8&useSSL=truespring.datasource.username=rootspring.datasource.password=root# spring data jpaspring.jpa.hibernate.ddl-auto=nonespring.jpa.hibernate.use-new-id-generator-mappings=falsespring.jpa.database-platform=org.hibernate.dialect.MySQLDialectspring.jpa.show-sql=false

主要配置数据库连接信息和JPA的配置项,JPA使用Hibernate实现。

0x06:数据库持久化换成JpaMetricsRepository实现

找到如下两个类

com.alibaba.csp.sentinel.dashboard.controller.MetricControllercom.alibaba.csp.sentinel.dashboard.metric.MetricFetcher

在metricStore属性上添加多一个@Qualifier("jpaMetricsRepository")注解,如下图

5ca7931ba9bdd59290361b2ee4a89688.png
146f769280e197c744fa14c070cf2508.png

0x07:验证

设置sentinel-dashboard工程的启动参数

-Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard

具体可以参考【 Sentinel如何进行流量监控 】;可以发现数据已经保存到MySQL数据库。

备注:以上代码改造都是在sentinel-dashboard项目上。

参考:https://www.cnblogs.com/cdfive2018/p/9838577.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值