网站首页 > 技术文章 正文
目录
- 前言
- 分析
- 方案
- 代码
- 监控
- 方案优化
- 总结
前言
之前老顾介绍了Sentinel相关的文章,小伙伴在生产实践中不知道有没有这个疑问?我们的Sentinel控制台监控的数据只能看最近5分钟的,如图
那么就导致历史数据是查看不了的,那肯定是不行的,在生产环境中我们最起码能够看到最近几天甚至几个月的监控数据,方便我们排查出哪些时间段/哪些天,哪些接口会到达什么样的QPS;方便我们对整体系统的QPS、以及异常情况有基本的了解。
如果要做到这些,就需要做到对这些数据进行持久化,而不能只保存在内存中。那我们今天就来介绍一下怎么改造Sentinel控制台,可以达到持久化的目的。
分析
Sentinel客户端会记录资源访问的秒级数据(若没有访问则不进行记录)并保存在本地日志中。Sentinel 控制台可以通过 Sentinel 客户端预留的 HTTP API 从秒级监控日志中拉取监控数据,并进行聚合。
目前Sentinel控制台中监控数据聚合后直接存在内存中,未进行持久化,且仅保留最近 5 分钟的监控数据。核心思想就是实现MetricsRepository接口实现,源码如下
MetricsRepository定义了以下接口:
save 与 saveAll:存储对应的监控数据
queryByAppAndResourceBetween:查询某段时间内的某个应用的某个资源的监控数据listResourcesOfApp:查询某个应用下的所有资源
现在Sentinel控制台只实现了内存InMemoryMetricsRepository,接口可传入自定义范型
上面默认的监控数据类型为MetricEntity,包含应用名称、时间戳、资源名称、异常数、请求通过数、请求拒绝数、平均响应时间等信息。
对于监控数据的存储,用户需要根据自己的存储精度,来考虑如何存储这些监控数据。部署多个控制台实例时,通常需要仔细设计下监控拉取和写入策略。
我们知道了Sentinel的实现,那我们持久化监控的方案是什么呢?
方案
我们把监控数据持久化到哪里呢?能想到的就是数据库,但不要选择mysql数据库,而是选择带时序功能的数据库方案,可采用主流的InfluxDB时序数据库
具体InfluxDB和mysql有什么区别,可网上查看
持久化是第一步,我们下一步还需要用图表的方式展现出来,我们第一个能够想到的方案就是Grafana。
小伙伴如果不了解,自行网补
这样我们具体的方案就有了,如图
代码
现在Sentinel控制台项目pom.xml中引入influxdb包
org.influxdb
influxdb-java
2.21
封装一个influxdb工具类
1、url、username、password用于存储InfluxDB的连接、用户名、密码信息,定义为static属性,因此在set方法上使用@Value注解从配置文件读取属性值;
2、resultMapper用于查询结果到实体类的映射;
3、init方法用于初始化url、username、password;
4、process为通用的处理方法,负责打开关闭连接,并且调用InfluxDBCallback回调方法;
5、insert为插入数据方法,配合InfluxDBInsertCallback回调使用;
6、query为通用的查询方法,配合InfluxDBQueryCallback回调方法使用,返回QueryResult对象;
7、queryList为查询列表方法,调用query得到QueryResult,再通过resultMapper转换为List<实体类>;
在resources目录下的application.properties文件中,增加InfluxDB的配置:
influxdb.url=http://127.0.0.1:8086
influxdb.username=admin
influxdb.password=admin
在datasource.entity包下,新建influxdb包,下面新建sentinel_metric数据表(measurement)对应的实体类MetricPO:
该类参考MetricEntity创建,加上influxdb-java包提供的注解
通过@Measurement(name = "sentinel_metric")指定数据表(measurement)名称
time作为时序数据库的时间列;
app、resource设置为tag列,通过注解标识为tag=true;
其它字段为filed列;
接着在InMemoryMetricsRepository所在的repository.metric包下新建InfluxDBMetricsRepository类,实现MetricsRepository
其中:
1、save、saveAll方法通过调用InfluxDBUtils.insert和InfluxDBInsertCallback回调方法,往sentinel_db库的sentinel_metric数据表写数据;
2、saveAll方法不是循环调用save方法,而是在回调内部循环Iterable
metrics处理,这样InfluxDBFactory.connect连接只打开关闭一次; 3、doSave方法中,.time(DateUtils.addHours(metric.getTimestamp(), 8).getTime(), TimeUnit.MILLISECONDS)
4、
queryByAppAndResourceBetween、listResourcesOfApp里面的查询方法,使用InfluxDB提供的类sql语法,编写查询语句即可。
最后一步,在MetricController、MetricFetcher两个类,找到metricStore属性,在@Autowired注解上面加上@Qualifier("influxDBMetricsRepository")注解:
到此持久化就完成了,可以启动测试一下,就可以发现influxdb进入了监控数据
监控
部署安装Grafana这里就不介绍了,自行网补;Grafana有模板的概念,只要配置了模板,然后动态传入参数即可快速生成多个使用相同模板的不同指标数据的图表。
添加模板
然后配置SQL执行查询,即时可看到效果
配置好以后使用模板功能查看多个接口的流控指标监控
具体Grafana配置,小伙伴们可以自行网补
方案优化
上面我们已经实现了监控数据持久化到influxDB中了,但是我们会发现一写问题
1、sentinel-dashboard目前是每隔一秒从所有的客户端同步一次数据, 集群庞大的情况下,控制台需要拉取很多客户端的数据,效率很低且不稳定,看源码
2、sentinel-dashboard收集到数据以后直接插入数据库没有缓冲,吞吐量低,性能低
基于上面的问题我们可以优化一下方案
优化方案
优化点
1、增加一个服务Sentinel Server,用来就是收集监控数据
2、Sentinel客户端主动推送给Sentinel Server,不需要去拉;这样就解决了集群大的情况
3、增加kafka消息中间件,做了数据的缓冲,性能以及吞吐量会大大提升
4、Sentinel Server发布以及订阅监控数据消息
这个优化方案就要把Sentinel控制台中的监控业务移除掉
总结
这篇文章最主要解决了监控数据持久化监控的问题,涉及到最终的优化方案有时间老顾后续文章介绍,希望这篇文章能够帮助小伙伴们,谢谢!!!
推荐阅读
Sentinel全局Feign默认熔断降级策略的思考
你所不知道的头部参数传递的坑,来吧!抓紧出坑
5分钟让你理解K8S必备架构概念,以及网络模型(一)
5分钟让你理解K8S必备架构概念,以及网络模型(二)
5分钟让你理解K8S必备架构概念,以及网络模型(三)
大厂如何基于binlog解决多机房同步mysql数据(一)?
大厂如何基于binlog解决多机房同步mysql数据(二)?
基于binlog的canal组件有哪些使用场景(三)?
基于binlog日志之canal企业应用及高可用原理(四)?
可用于大型应用的微服务生态灰度发布如何实现?
一线大厂级别公共Redis集群监控,细化到每个项目实例
Sharding-jdbc的实战入门之水平分表(一)
Sharding-Jdbc之水平分库和读写分离(二)
猜你喜欢
- 2025-03-29 深入解构LVM:从物理卷到逻辑卷(linux逻辑卷和物理卷)
- 2025-03-29 MyBatis接口绑定有几种实现方式,分别是怎么实现的?
- 2025-03-29 Spring Security在前后端分离项目中的使用
- 2025-03-29 开源微服务编排框架:Netflix Conductor
- 2025-03-29 Spring框架中的两大事务管理神器:声明式与编程式
- 2025-03-29 Docker Device Mapper(device mapper)
- 2025-03-29 拒绝写重复代码,试试这套开源的 SpringBoot 组件
- 2025-03-29 MyBatis的三种分页方式,你学废了吗?
- 2025-03-29 refresh是什么?Spring refresh的12个步骤
- 2025-03-29 基于LOGBACK实现的分布式日志跟踪
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)