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. 验证查询数据库

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/178623.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

leetcode:520. 检测大写字母

一、题目&#xff1a; 链接&#xff1a;520. 检测大写字母 - 力扣&#xff08;LeetCode&#xff09; 函数原型&#xff1a;bool detectCapitalUse(char* word) 二、思路&#xff1a; 本题较为简单&#xff0c;分为三种情况&#xff1a; 1.首字母大写&#xff0c;其余小写 2.首字…

Github Copilot AI编码完成工具

目录 一、GitHub Copilot 1、简介 2、工作原理 3、功能 二、GitHub Copilot X 1、什么是 GitHub Copilot X 2、GitHub Copilot X 的功能 三、支持、使用 1、支持 2、使用 四、实际研究、验证(代码方向) 1、代码生成 2、代码提示 3、生成测试用例 4、代码解释 5…

【Axure高保真原型】树形表格

今天和大家分享树形表格的原型模板&#xff0c;点击树的箭头可以打开或者收起子节点&#xff0c;点击表格内容&#xff0c;可以选中该行内容实现高亮变色效果&#xff0c;树形表格是通过中继器制作的&#xff0c;使用简单&#xff0c;只需要按要求填写中继器表格即可&#xff0…

深度学习常见激活函数:ReLU,sigmoid,Tanh,softmax,Leaky ReLU,PReLU,ELU整理集合,应用场景选择

文章目录 1、ReLU 函数&#xff08;隐藏层中是一个常用的默认选择&#xff09;1.1 优点1.2 缺点 2、sigmoid 函数2.1 优点2.2 缺点 3、Tanh 函数3.1 优点3.2 缺点 4、softmax 函数&#xff08;多分类任务最后一层都会使用&#xff09;5、Leaky ReLU 函数5.1 优点5.2 缺点 6、PR…

2023.11.22 -数据仓库的概念和发展

目录 https://blog.csdn.net/m0_49956154/article/details/134320307?spm1001.2014.3001.5501 1经典传统数仓架构 2离线大数据数仓架构 3数据仓库三层 数据运营层,源数据层&#xff08;ODS&#xff09;&#xff08;Operational Data Store&#xff09; 数据仓库层&#…

【深度学习】不用Conda在PP飞桨Al Studio三个步骤安装永久PyTorch环境

在 PaddlePaddle AI Studio 中使用 Python 虚拟环境安装 PyTorch 免责声明 在阅读和实践本文提供的内容之前&#xff0c;请注意以下免责声明&#xff1a; 侵权问题: 本文提供的信息仅供学习参考&#xff0c;不用做任何商业用途&#xff0c;如造成侵权&#xff0c;请私信我&am…

基于SSM的济南旅游网站设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

数字逻辑电路基础-时序逻辑电路之锁存器

文章目录 一、锁存器简介二、verilog源码三、综合及仿真结果 一、锁存器简介 本文介绍数字逻辑电路中一种常用的基础时序逻辑电路-锁存&#xff0c;顾名思义&#xff0c;它的功能就是将输入在控制信号有效时透明传输到输出端&#xff0c;当控制信号无效时&#xff0c;输出值保…

微信小程序蓝牙连接 uniApp蓝牙连接设备

蓝牙列表期待效果 代码 <template><view class"bluetooth-list"><view class"align-items option" style"justify-content: space-between;" v-for"item in bluetoothList" :key"item.deviceId"><vie…

万字解析设计模式之组合模式、亨元模式

一、组合模式 1.1概述 组合模式是一种结构型设计模式&#xff0c;它允许将对象组合成树形结构&#xff0c;以表示“部分-整体”的层次结构。组合模式使得客户端可以一致地对待单个对象和对象组合&#xff0c;从而将复杂的层次结构展现为一个统一的树形结构。 在组合模式中&…

Audition 2024 24.0.0.46(音频剪辑)

Audition 2024是一款非常棒的音频编辑和混合软件&#xff0c;提供了广泛的工具和功能&#xff0c;用于创建、编辑、混合和设计音效。这款软件旨在加速音频和视频制作工作流程&#xff0c;提供具有原始音效的高质量混音。其界面构成清晰&#xff0c;操作简便&#xff0c;适合专业…

【python】python旅游网数据抓取分析(源码+论文)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

开发上门送桶装水小程序要考虑哪些业务场景

上门送水业务已经有很长一段时间了&#xff0c;但是最开始都是给用户发名片、贴小广告&#xff0c;然后客户电话订水&#xff0c;水站工作人员再上门去送&#xff0c;这种人工记单和派单效率并不高&#xff0c;并且电话沟通中也比较容易出现偏差&#xff0c;那么根据这个情况就…

【Docker】从零开始:6.配置镜像加速器

【Docker】从零开始&#xff1a;5.配置镜像加速器 什么是镜像加速器&#xff1f;为什么要配置docker镜像加速器?常见的Docker镜像加速器有哪些&#xff1f;如何申请Docker镜像加速器如何配置Docker镜像加速器 什么是镜像加速器&#xff1f; 镜像加速器是一个位于Docker Hub之…

UDP中connect的作用

udpclientNoConnect.c里边的内容如下&#xff1a; #include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<arpa/inet.h> #include<sys/socket.h> #include <errno.h> #include <syslog.h…

七、通过libfdk_aac编解码器实现aac音频和pcm的编解码

前言 测试环境&#xff1a; ffmpeg的4.3.2自行编译版本windows环境qt5.12 AAC编码是MP3格式的后继产品&#xff0c;通常在相同的比特率下可以获得比MP3更高的声音质量&#xff0c;是iPhone、iPod、iPad、iTunes的标准音频格式。 AAC相较于MP3的改进包含&#xff1a; 更多的采…

在AWS VPC中运行Nagios检查时指定自定义DNS解析器的选项

在AWS VPC中运行Nagios检查&#xff0c;并希望能够指定自定义DNS解析器来处理请求。我想使用Python requests库来实现这个目标。 根据问题描述&#xff0c;您想在AWS VPC中运行Nagios检查&#xff0c;并希望使用Python的requests库来指定自定义DNS解析器。 要解决这个问题&…

[开源]Web端的P2P文件传输工具,简单安全高效的P2P文件传输服务

一、开源项目简介 小鹿快传 - 在线P2P文件传输工具 小鹿快传是一款Web端的P2P文件传输工具&#xff0c;使用了WebRTC技术实现P2P连接和文件传输。 二、开源协议 使用MIT开源协议 三、界面展示 产品截图 四、功能概述 简单安全高效的P2P文件传输服务 小鹿快传是一款Web端…

php文件上传例子

目录结构&#xff1a; index.html代码&#xff1a; <!DOCTYPE html> <html><head><title>文件上传</title><meta charset"utf-8"></head><body><form action"./up.php" method"post" encty…

python趣味编程-5分钟实现一个太空大战游戏(含源码、步骤讲解)

飞机战争游戏系统项目是使用Python编程语言开发的,是一个简单的桌面应用程序。 Python 中的飞机战争游戏使用pygame导入和随机导入。 Pygame 是一组跨平台的 Python 模块,专为编写视频游戏而设计。它包括设计用于 Python 编程语言的计算机图形和声音库。