官方文档  https://sentinelguard.io/zh-cn/

wiki: 在生产环境中使用-Sentinel

      

推荐方案:持久化到 时序数据库InfluxDB  ; 结合Grafana 可视化平台 将监控数据进行多维度的统计和呈现 (百度)。

需求只保留三天数据,所以持久化到mysql数据库,然后定时删除之前的数据:

         

  • 解压之后通过IDE直接打开:

      

  • 持久化到数据库,需要在项目中添加相关依赖,在配置文件中进行配置(可以自行百度选择交互方式,本文采用JPA与数据库交互);

创建数据表:

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',
`exception_qps` INT COMMENT '发送异常的次数',
`rt` DOUBLE COMMENT '所有successQps的rt的和',
`_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;

#索引根据需求自行添加
 pom:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>${spring.boot.version}</version>
</dependency>
数据库驱动
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
</dependency>


application.properties :
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://地址:3306/数据库名
spring.datasource.username=root
spring.datasource.password=123456

spring.jpa.hibernate.ddl-auto=none
spring.jpa.hibernate.use-new-id-generator-mappings=false
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
spring.jpa.show-sql=false
  • 在 datasource/entity下创建表对应的实体类
@Data
@Entity
@Table(name = "sentinel_metric")
public class MetricDTO implements Serializable { 

  private static final long serialVersionUID = 20230216L;
  /**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;
}
  • 在  repository/metric 下创建MetricsRepository接口的实现类:

@Transactional
@Repository("jpaMetricsRepository")
public class JpaMetricsRepository implements MetricsRepository<MetricEntity> {
@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<MetricEntity> metrics) {
if (metrics == null) {
return;
}
metrics.forEach(this::save);
}

@Override
public List<MetricEntity> queryByAppAndResourceBetween(String app, String resource, long startTime, long endTime) {
     //开始时间和结束时间可以在MetricController中修改,默认查询最新一分钟之内的数据
     List<MetricEntity> results = new ArrayList<MetricEntity>();
        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<MetricDTO> metricDTOList = query.getResultList();
if (CollectionUtils.isEmpty(metricDTOList)) {
return results;
}
for (MetricDTO metricDTO : metricDTOList) {
MetricEntity metricEntity = new MetricEntity();
BeanUtils.copyProperties(metricDTO, metricEntity);
results.add(metricEntity);
}
return results;
}

@Override
public List<String> listResourcesOfApp(String app) {
List<String> 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 * 60;
Query query = em.createQuery(hql.toString());
query.setParameter("app", app);
query.setParameter("startTime", Date.from(Instant.ofEpochMilli(startTime)));
List<MetricDTO> metricDTOList = query.getResultList();
if (CollectionUtils.isEmpty(metricDTOList)) {
return results;
}
List<MetricEntity> metricEntities = new ArrayList<MetricEntity>();
for (MetricDTO metricDTO : metricDTOList) {
MetricEntity metricEntity = new MetricEntity();
BeanUtils.copyProperties(metricDTO, metricEntity);
metricEntities.add(metricEntity);
}
Map<String, MetricEntity> 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());
}
}
  • 指定MetricsRepository依赖注入的类型:

       

  • 运行项目,访问 http://localhost:8080/   输入用户名和密码 都为 sentinel  登录后界面:

      

  • 至此控制台项目改造完成。

本地搭建客户端项目:创建springboot项目 :

注意:搭建过程中因为sentinel版本为1.8.6,springboot版本过低导致报错,错误日志会提示采用2.6.x和2.7.x版本,最终选择升级springboot 版本为 2.6.14

sentinel控制端版本和sentinel客户端版本要对应,否则会报错。

pom文件:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.14</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>rta-consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>rta-consumer</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<log4j2.version>2.17.1</log4j2.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency> <dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency> <!-- 限流、熔断框架 不连通客户端本地可用 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2021.0.1.0</version>
</dependency> <dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<version>1.8.6</version>
</dependency> <!-- sentinel客户端与dashboard通信依赖 版本要和控制端一致-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.8.6</version>
</dependency> </dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>

配置文件 application.yml:
server:
port: 8090

spring:
application:
name: springboot-sentinel
cloud:
sentinel:
transport:
dashboard: 127.0.0.1:8080 #控制台地址

log4j2.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration monitorinterval="10">
<Appenders>
<!--控制台输出配置-->
<Console name="Console" target="SYSTEM_OUT">
<!--日志输出样式-->
<PatternLayout>
<Pattern>%d[%p] [%t] %c[%M(%L)] - %m%n</Pattern>
</PatternLayout>
</Console>
</Appenders>

<Loggers>
<!--控制器默认的looger-->
<Root level="info">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>

代码:
@Controller
@RequestMapping("/test")
@Slf4j
public class TestController {

@Autowired
private TestService testService;

@RequestMapping("query")
@ResponseBody
public String query() {
String query = testService.query();
log.info("查询");
return query;
}
}

public interface TestService {

String query();
}
@Service
public class TestServiceImpl implements TestService {

@Override
@SentinelResource(value = "query")
public String query() {

return "service";
}
}
  • 启动客户端,访问对应地址,刷新控制台页面:

        

数据库表中数据添加成功:

  



sentinel监控数据持久化&本地测试的更多相关文章

  1. Sentinel上生产环境只差一步,监控数据持久化

    之前介绍了Sentinel相关的文章,小伙伴在生产实践中不知道有没有这个疑问?我们的Sentinel控制台监控的数据只能看最近5分钟的,如图 那么就导致历史数据是查看不了的,那肯定是不行的,在生产环境 ...

  2. sentinel控制台监控数据持久化【InfluxDB】

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

  3. sentinel控制台监控数据持久化【MySQL】

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

  4. iOS开发——数据持久化&本地数据的存储(使用NSCoder将对象保存到.plist文件)

    本地数据的存储(使用NSCoder将对象保存到.plist文件)   下面通过一个例子将联系人数据保存到沙盒的“documents”目录中.(联系人是一个数组集合,内部为自定义对象).   功能如下: ...

  5. js数据持久化本地数据存储-JSON.parse和JSON.stringify的区别

    JSON.stringify()的作用是将 JavaScript 值转换为 JSON 字符串, 而JSON.parse()可以将JSON字符串转为一个对象. 简单点说,它们的作用是相对的,我用JSON ...

  6. SpringBoot 2.0 + InfluxDB+ Sentinel 实时监控数据存储

    前言 阿里巴巴提供的控制台只是用于演示 Sentinel 的基本能力和工作流程,并没有依赖生产环境中所必需的组件,比如持久化的后端数据库.可靠的配置中心等.目前 Sentinel 采用内存态的方式存储 ...

  7. React-Native 之 GD (十三)数据持久化(realm) 及 公共Cell

    1.数据持久化 数据持久化是移动端的一个重要部分,刚发现 Realm 原来已经支持 React-Native 了 步骤一: 引入 realm $ npm install realm --save 步骤 ...

  8. OC 数据持久化(数据本地化)- 本地存储

    // // ViewController.m // IOS_0113_本地存储 // // Created by ma c on 16/1/13. // Copyright (c) 2016年 博文科 ...

  9. docker mysql 数据持久化到本地、设置不区别表名大小写-清风柳絮-51CTO博客

    原文:docker mysql 数据持久化到本地.设置不区别表名大小写-清风柳絮-51CTO博客 Docker MySQL 把数据存储在本地目录,很简单,只需要映射本地目录到容器即可 1.加上-v参数 ...

  10. Docker数据持久化及实战(Nginx+Spring Boot项目+MySQL)

    Docker数据持久化: Volume: (1)创建mysql数据库的container docker run -d --name mysql01 -e MYSQL_ROOT_PASSWORD= my ...

随机推荐

  1. 强大的word插件,让工作更高效:不坑盒子 2023版

    不坑盒子简介 很多朋友在工作过程中需要对Word文档进行编辑处理,如果想让Word排版更有效率可以试试小编带来的这款不坑盒子软件,这是一个非常好用的插件工具,专门应用在Word文档中,支持Office ...

  2. Spring IOC官方文档学习笔记(十)之类路径扫描与组件管理

    1.@Component注解与其衍生注解 (1) 在Spring中,@Component注解用于说明某个类是一个bean,之后Spring在类路径扫描过程中会将该bean添加至容器中;@Compone ...

  3. 2022.2.1最新版本的IDEA

          一.下载破解工具.激活码 激活工具下载链接:https://note.youdao.com/s/1ANz2F3o   6G5NXCPJZB-eyJsaWNlbnNlSWQiOiI2RzVO ...

  4. 基于ROS的串口底层写法

    serial_device.cpp #include "serial_device.h" namespace roborts_sdk { SerialDevice::SerialD ...

  5. 2.17 win32 按钮事件的处理

    按钮的本质就是窗口 点击查看代码 void CreateButton(HWND hwnd) { HWND hwndPushButton; HWND hwndCheckBox; HWND hwndRad ...

  6. Linux CentOS 7 磁盘扩容(原有磁盘扩容,非新增磁盘)

    背景: 接上篇  https://www.cnblogs.com/si-yuan/p/17148835.html,只是展示出了磁盘大小,还需进行如下操作,去完成原有磁盘的扩容. ----------- ...

  7. Swiper第一页与最后一页禁止滑动

    resistanceRatio抵抗率.边缘抵抗力的大小比例.值越小抵抗越大越难将slide拖离边缘,0时完全无法拖离. mounted: function() { let _this = this; ...

  8. 最新版 IDEA 2022.3.2 最优开发配置

    最新版 IDEA 2022.3.2 最优开发配置 教程最后更新时间:2023.3.1 安装好 IntelliJ IDEA 后,进行如下的初始化操作,工作效率提升10倍. 目录 一.全局配置 如何进入全 ...

  9. Docker安装和基础命令

    每个优秀的人,背后都有一段沉默的时光 前言 学习Docker基础知识 安装 docker常见的有3种安装方式,yum.rpm包.脚本. 我们采用相对简单但对各种环境比较友好的方式:(关防火墙和seli ...

  10. Nginx 虚拟主机中配置 server_name ⼀个server块中配置多个站点 ⼀个站点配置多个⼆级域名

    ⼀个server块中配置多个站点 server { listen 80; server_name ~^(www.)?(.+)$; index index.php index.html; root /h ...