作者:橙色马路
从马楠的上一篇文章中,我们已经了解到Prometheus的一大优势,是可以在应用内定义自己的指标做监控。我们在 SpringBoot 做微服务的生产环境中,使用自定义指标监控诸多物联网传感器,时序数据结构简单清晰,监控与统计反应迅捷,效果良好。
SpringBoot 2的actuator中默认使用Micrometer作为指标支持库。本身已经内置了许多开箱即用的指标。自定义的指标注册以后,也会被融合在相同的uri(/actuator/prometheus)中统一输出,非常方便。
1. 注册表(Registry)
Prometheus是用定时Pull方式去服务器拉取指标数据,以拉取的时间打点做时间轴,形成时间序列。应用服务器只需暴露当下时刻的指标值即可,所以数据模型本质是一个个KV键值对,存放在全局的容器,Prometheus来获取的时候,将容器内的值格式化输出。此处的容器即为计量注册表(MeterRegistry) 。
几种内置的Registry如下:
SimpleMeterRegistry:极简实现,数据存取在内存中,每项数据只保留最新一次的数值。默认SpringBoot会帮你autowire一个。
CompositeMeterRegistry:用组合模式帮你将多个注册表串联成一个对外接口。全局的Metrics.globalRegistry就是这么个组合模式接口
2. 两种常用指标类型(Metric Type)
gauge: 可增可减计数器,反应某值当前一刻状态。比如称重传感器的当前重量,温度传感器的当前温度。
方式一:
Gauge.builder("gn.temperature.gauge", new AtomicInteger(37), AtomicInteger::get)
方式二:
registry.gauge("gn.temperature.gauge", Tags.of("site", "SiteA", "cab", "cab01"), new AtomicInteger(37));
两者等价,会输出成如下指标:
# HELP gn_temperature_gauge_value for cab temperature
# TYPE gn_temperature_gauge_value
gn_temperature_gauge_value{application="xxx",cab="cab01",site="SiteA",} 37.0
注意定义的名称转换:其中"."被换成了"_",gauge类型的指标最后加上了"_value"做结尾。指标命名只能为ASCII字母、数字、下划线和冒号,且必须配正则表达式[a-zA-Z_:][a-zA-Z0-9_:]*
counter:只增不减计数器,是Gauge的一个特例。适用于只有服务器重启时候才会重置的计数场景。比如"用户访问次数",某接口失败次数"等等。API 使用方式类似。
Counter counter = Counter.builder("gn.beat.counter")
.tags("site", "SiteA", "function", "foo")
.description("for request errors")
.register(registry);
counter.increment();
会输出成如下指标:
# HELP gn_beat_counter_total for request errors
# TYPE gn_beat_counter_total counter
gn_beat_counter_total{application="xxx",function="foo",site="SiteA",} 1.0
3. 融入到系统的方式
方式一,业务系统埋点:
@Component
public class SampleBean {
private final Counter counter;
public SampleBean(MeterRegistry registry) {
this.counter = registry.counter("gn.beat.counter");
}
public void handleMessage(String message) {
this.counter.increment();
// handle message implementation
}
}
方式二:MeterBinder
SpringBoot中提供了MeterBinder接口用于申明与注册meterRegistry。自定义Metrics只需要实现MeterBinder接口,Spring会自动发现并完成后续的杂活。
@Bean
public class MyMetrics implements MeterBinder {
@Override
public void bindTo(MeterRegistry meterRegistry) {
//此处添加相关指标
meterRegistry.gauge("gn.temperature.gauge", Tags.of("site", "SiteA", "cab", "cab01"), new AtomicInteger(37));
}
}
Spring优秀的解耦架构还可以方便地搭配自定义配置项方式使用。
指标值注册到registry中默认为弱引用,若函数调用调用周期结束,则该值会被 Java 给标记并 GC 掉。对应的指标输出的值则会很快会变成了NaN。
此种短状态适用于心跳类型的指标,在预警系统中可以及时发现没有按时上报的点。
但对于相对长时间想保持住特定指标值,需要显式给到对应变量强引用。比如使用一个实例化的HashMap来 cache 相关的值。
如上段代码中,方式一为强引用,方式二则弱引用。
名称 + {一组tag} + 值 为一指标形式。
如某库位温度指标形式如下:
gn_temperature_gauge_value{application="xxx",cab="cab01",site="SiteA"} 37.0
tag中值为 String 型,尽量选取『可识别』,『有限集合』的值作为 tag,比如主机,柜号,库位等等。每一个tag值都会产生一个维度,不同的 tag值+名称会被记录成不同的时间序列。
某些很有潜力膨胀到"无限量"的值如各种ID、邮件地址、时间戳等,就不适宜选做 tag的值
后期若使用 grafana 绘制特定指标变化图,不同时间序列也会对应到不同的多条曲线。
指标值为 double 型: 对于自定义的数值型,如温度,访问次数等的指标,原样输出即可。
若输入某些状态类的值,可定义成数值型。比如 Prometheus 中的存活状态指标 UP = 1。类似如某后台 Job 状态(pending, running, stopped),可依样定义为10,20,30。
对于Prometheus这类基于Pull模式的监控平台而言,往往由中心server来决定采集的目标有多少有哪些,所以在微服务在集群模式下,多端Metrics的聚合可通过Prometheus的Pull模式天然汇聚。
通过服务发现形式,获取到当前集群中所有节点的信息,更新配置文件并且重建抓取的列表,将分散的Metrics聚合到中心服务器。
Prometheus本身支持 DNS, Consul, Kubernetes, OpenStack, EC2 等发现机制。在Kubernetes下,可通过与Kubernetes API集成目前主要支持多服务发现模式,如Node、Service、Pod、Endpoints、Ingress等。
部署架构的示意图如下:
这部分由部署层实现,对应用层透明。
7. 关于作者
橙色马路:创业者,技术管理与架构,ex-Oracler。
相关参考:
https://micrometer.io/docs/concepts
https://spring.io/blog/2018/03/16/micrometer-spring-boot-2-s-new-application-metrics-collector
https://winderresearch.com/introduction-to-monitoring-microservices-with-prometheus/
本文分享自 云服务与SRE架构师社区 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!