Sentinel上生产环境只差一步,监控数据持久化
之前介绍了Sentinel相关的文章,小伙伴在生产实践中不知道有没有这个疑问?我们的Sentinel控制台监控的数据只能看最近5分钟的,如图
那么就导致历史数据是查看不了的,那肯定是不行的,在生产环境中我们最起码能够看到最近几天甚至几个月的监控数据,方便我们排查出哪些时间段/哪些天,哪些接口会到达什么样的QPS;方便我们对整体系统的QPS、以及异常情况有基本的了解。
如果要做到这些,就需要做到对这些数据进行持久化,而不能只保存在内存中。那我们今天就来介绍一下怎么改造Sentinel控制台,可以达到持久化的目的。同时用XMind画了一张导图记录Spring Cloud Alibaba的学习笔记(源文件对部分节点有详细备注和参考资料,由于太大就没展示全部,欢迎关注我的公众号:阿风的架构笔记 后台发送【导图】拿下载链接, 已经完善更新):
分析
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包
<dependency>
<groupId>org.influxdb</groupId>
<artifactId>influxdb-java</artifactId>
<version>2.21</version>
</dependency>
封装一个influxdb工具类
- url、username、password用于存储InfluxDB的连接、用户名、密码信息,定义为static属性,因此在set方法上使用@Value注解从配置文件读取属性值;
- resultMapper用于查询结果到实体类的映射;
- init方法用于初始化url、username、password;
- process为通用的处理方法,负责打开关闭连接,并且调用InfluxDBCallback回调方法;
- insert为插入数据方法,配合InfluxDBInsertCallback回调使用;
- query为通用的查询方法,配合InfluxDBQueryCallback回调方法使用,返回QueryResult对象;
- 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
其中:
- save、saveAll方法通过调用InfluxDBUtils.insert和InfluxDBInsertCallback回调方法,往sentinel_db库的sentinel_metric数据表写数据;
- saveAll方法不是循环调用save方法,而是在回调内部循环Iterable
metrics处理,这样InfluxDBFactory.connect连接只打开关闭一次; - doSave方法中,.time(DateUtils.addHours(metric.getTimestamp(), 8).getTime(), TimeUnit.MILLISECONDS)
- queryByAppAndResourceBetween、listResourcesOfApp里面的查询方法,使用InfluxDB提供的类sql语法,编写查询语句即可。
最后一步,在MetricController、MetricFetcher两个类,找到metricStore属性,
在@Autowired注解上面加上@Qualifier("influxDBMetricsRepository")注解:
到此持久化就完成了,可以启动测试一下,就可以发现influxdb进入了监控数据
监控
部署安装Grafana这里就不介绍了,自行网补;Grafana有模板的概念,只要配置了模板,然后动态传入参数即可快速生成多个使用相同模板的不同指标数据的图表。
添加模板
然后配置SQL执行查询,即时可看到效果
配置好以后使用模板功能查看多个接口的流控指标监控
具体Grafana配置,小伙伴们可以自行网补
方案优化
上面我们已经实现了监控数据持久化到influxDB中了,但是我们会发现一写问题
1、sentinel-dashboard目前是每隔一秒从所有的客户端同步一次数据, 集群庞大的情况下,控制台需要拉取很多客户端的数据,效率很低且不稳定,看源码
2、sentinel-dashboard收集到数据以后直接插入数据库没有缓冲,吞吐量低,性能低
基于上面的问题我们可以优化一下方案
优化方案
优化点
-
增加一个服务Sentinel Server,用来就是收集监控数据
-
Sentinel客户端主动推送给Sentinel Server,不需要去拉;这样就解决了集群大的情况
-
增加kafka消息中间件,做了数据的缓冲,性能以及吞吐量会大大提升
-
Sentinel Server发布以及订阅监控数据消息
这个优化方案就要把Sentinel控制台中的监控业务移除掉
总结
这篇文章最主要解决了监控数据持久化监控的问题,涉及到最终的优化方案有时间后续文章介绍,希望这篇文章能够帮助小伙伴们,谢谢!!!
看完三件事❤️
如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
- 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
- 关注公众号 『 阿风的架构笔记 』,不定期分享原创知识。
- 同时可以期待后续文章ing🚀
- 关注后回复【666】扫码即可获取架构进阶学习资料包