sentinel监控数据持久化&本地测试
官方文档 https://sentinelguard.io/zh-cn/
wiki: 在生产环境中使用-Sentinel
推荐方案:持久化到 时序数据库InfluxDB ; 结合Grafana 可视化平台 将监控数据进行多维度的统计和呈现 (百度)。
需求只保留三天数据,所以持久化到mysql数据库,然后定时删除之前的数据:
- 先下载源码进行扩展,选择对应版本的资源:https://github.com/alibaba/Sentinel/releases/tag/1.8.6
- 解压之后通过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监控数据持久化&本地测试的更多相关文章
- Sentinel上生产环境只差一步,监控数据持久化
之前介绍了Sentinel相关的文章,小伙伴在生产实践中不知道有没有这个疑问?我们的Sentinel控制台监控的数据只能看最近5分钟的,如图 那么就导致历史数据是查看不了的,那肯定是不行的,在生产环境 ...
- sentinel控制台监控数据持久化【InfluxDB】
根据官方wiki文档,sentinel控制台的实时监控数据,默认仅存储 5 分钟以内的数据.如需持久化,需要定制实现相关接口. https://github.com/alibaba/Sentinel/ ...
- sentinel控制台监控数据持久化【MySQL】
根据官方wiki文档,sentinel控制台的实时监控数据,默认仅存储 5 分钟以内的数据.如需持久化,需要定制实现相关接口. https://github.com/alibaba/Sentinel/ ...
- iOS开发——数据持久化&本地数据的存储(使用NSCoder将对象保存到.plist文件)
本地数据的存储(使用NSCoder将对象保存到.plist文件) 下面通过一个例子将联系人数据保存到沙盒的“documents”目录中.(联系人是一个数组集合,内部为自定义对象). 功能如下: ...
- js数据持久化本地数据存储-JSON.parse和JSON.stringify的区别
JSON.stringify()的作用是将 JavaScript 值转换为 JSON 字符串, 而JSON.parse()可以将JSON字符串转为一个对象. 简单点说,它们的作用是相对的,我用JSON ...
- SpringBoot 2.0 + InfluxDB+ Sentinel 实时监控数据存储
前言 阿里巴巴提供的控制台只是用于演示 Sentinel 的基本能力和工作流程,并没有依赖生产环境中所必需的组件,比如持久化的后端数据库.可靠的配置中心等.目前 Sentinel 采用内存态的方式存储 ...
- React-Native 之 GD (十三)数据持久化(realm) 及 公共Cell
1.数据持久化 数据持久化是移动端的一个重要部分,刚发现 Realm 原来已经支持 React-Native 了 步骤一: 引入 realm $ npm install realm --save 步骤 ...
- OC 数据持久化(数据本地化)- 本地存储
// // ViewController.m // IOS_0113_本地存储 // // Created by ma c on 16/1/13. // Copyright (c) 2016年 博文科 ...
- docker mysql 数据持久化到本地、设置不区别表名大小写-清风柳絮-51CTO博客
原文:docker mysql 数据持久化到本地.设置不区别表名大小写-清风柳絮-51CTO博客 Docker MySQL 把数据存储在本地目录,很简单,只需要映射本地目录到容器即可 1.加上-v参数 ...
- Docker数据持久化及实战(Nginx+Spring Boot项目+MySQL)
Docker数据持久化: Volume: (1)创建mysql数据库的container docker run -d --name mysql01 -e MYSQL_ROOT_PASSWORD= my ...
随机推荐
- Rust一些学习文档
<Rust 烹饪书>https://llever.com/rust-cookbook-zh/intro.zh.html <Rust高级编程>https://learnku.co ...
- Spring Cloud 2022.0.1 Spring Cloud Zookeeper4.0
官网: https://spring.io/ 左侧菜单 向下找到 spring Cloud Zookeeper 所有我们希望看到的都在 Reference Doc 中,点击进入 连接zookeeper ...
- JAVA虚拟机17---栈帧(局部变量表-操作数栈-动态连接-返回地址)
借鉴:转https://blog.csdn.net/u011069294/article/details/107106755,他的虚拟机专栏:https://blog.csdn.net/u011069 ...
- 周末折腾了两天,踩了无数个坑,终于把win7装成了centos7
上周五的时候,突发奇想,想把自己的Thinkpad E430C的操作系统装成linux. 熟悉电脑的都知道Thinkpad E430C很古老了,现在算来从2012年买来,到现在已经经历了10个年头了. ...
- 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 ...
- 图卷积神经网络分类的pytorch实现
图神经网络(GNN)目前的主流实现方式就是节点之间的信息汇聚,也就是类似于卷积网络的邻域加权和,比如图卷积网络(GCN).图注意力网络(GAT)等.下面根据GCN的实现原理使用Pytorch张量,和调 ...
- 免杀之:Python加载shellcode免杀
免杀之:Python加载shellcode免杀 目录 免杀之:Python加载shellcode免杀 1 Python 加载Shellcode免杀 使用Python可以做一些加密.混淆,但使用Pyth ...
- 在线工具帮助医生在社区转诊时甄别SpA患者
在线工具帮助医生在社区转诊时甄别SpA患者 Habibi S, et al. Rheumatology 2016. Present ID: 202. 背景:目前已开发了多种转诊策略以优化脊柱关节炎(S ...
- 代码随想录算法训练营day08 | leetcode 344.反转字符串/541. 反转字符串II / 剑指Offer05.替换空格/151.翻转字符串里的单词/剑指Offer58-II.左旋转字符串
基础知识 // String -> char[] char[] string=s.toCharArray(); // char[] -> String String.valueOf(str ...
- Mars3D与第三方集成
1. 引言 Mars3D是基于Cesium的Web端的三维GIS库,对Cesium做了进一步封装和扩展 Mars3D官网:Mars3D三维可视化平台 | 火星科技 Mars3D开发手册:开发教程 - ...