官方文档  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. Rust一些学习文档

    <Rust 烹饪书>https://llever.com/rust-cookbook-zh/intro.zh.html <Rust高级编程>https://learnku.co ...

  2. Spring Cloud 2022.0.1 Spring Cloud Zookeeper4.0

    官网: https://spring.io/ 左侧菜单 向下找到 spring Cloud Zookeeper 所有我们希望看到的都在 Reference Doc 中,点击进入 连接zookeeper ...

  3. JAVA虚拟机17---栈帧(局部变量表-操作数栈-动态连接-返回地址)

    借鉴:转https://blog.csdn.net/u011069294/article/details/107106755,他的虚拟机专栏:https://blog.csdn.net/u011069 ...

  4. 周末折腾了两天,踩了无数个坑,终于把win7装成了centos7

    上周五的时候,突发奇想,想把自己的Thinkpad E430C的操作系统装成linux. 熟悉电脑的都知道Thinkpad E430C很古老了,现在算来从2012年买来,到现在已经经历了10个年头了. ...

  5. ClickHouse exception, code: 62, host: hadoop102, port: 8123; Code: 62, e.displayText() = DB::Exception: Syntax error: failed at position 183 (end of query):

    报错 ClickHouse exception, code: 62, host: hadoop102, port: 8123; Code: 62, e.displayText() = DB::Exce ...

  6. 图卷积神经网络分类的pytorch实现

    图神经网络(GNN)目前的主流实现方式就是节点之间的信息汇聚,也就是类似于卷积网络的邻域加权和,比如图卷积网络(GCN).图注意力网络(GAT)等.下面根据GCN的实现原理使用Pytorch张量,和调 ...

  7. 免杀之:Python加载shellcode免杀

    免杀之:Python加载shellcode免杀 目录 免杀之:Python加载shellcode免杀 1 Python 加载Shellcode免杀 使用Python可以做一些加密.混淆,但使用Pyth ...

  8. 在线工具帮助医生在社区转诊时甄别SpA患者

    在线工具帮助医生在社区转诊时甄别SpA患者 Habibi S, et al. Rheumatology 2016. Present ID: 202. 背景:目前已开发了多种转诊策略以优化脊柱关节炎(S ...

  9. 代码随想录算法训练营day08 | leetcode 344.反转字符串/541. 反转字符串II / 剑指Offer05.替换空格/151.翻转字符串里的单词/剑指Offer58-II.左旋转字符串

    基础知识 // String -> char[] char[] string=s.toCharArray(); // char[] -> String String.valueOf(str ...

  10. Mars3D与第三方集成

    1. 引言 Mars3D是基于Cesium的Web端的三维GIS库,对Cesium做了进一步封装和扩展 Mars3D官网:Mars3D三维可视化平台 | 火星科技 Mars3D开发手册:开发教程 - ...