Prometheus
Prometheus是一个开源监控解决方案,用于收集和聚合指标作为时间序列数据。是继Kubernetes之后第二个CNCF托管项目
特点
普罗米修斯的主要特点是:
- 多维数据模型,其中时间序列数据由指标名称和键/值对标识
- PromQL,一种灵活的查询语言
- 不依赖分布式存储;单个服务器节点是自治的
- 时间序列收集通过 HTTP 上的 Pull 模型进行
- 通过中间网关支持推送时间序列
- 通过服务发现或静态配置发现Target
- 多种图形和仪表板支持
什么是指标?
指标是外行术语中的数值测量。术语时间序列是指随时间变化的记录。用户想要测量的内容因应用程序而异。对于 Web 服务器来说,它可能是请求时间;对于数据库,它可以是活动连接或活动查询的数量等。
指标在理解应用程序为何以某种方式运行方面发挥着重要作用。假设您正在运行一个 Web 应用程序并发现它很慢。要了解您的应用程序发生了什么,您将需要一些信息。例如,当请求数量较多时,应用程序可能会变慢。如果您有请求计数指标,则可以确定原因并增加处理负载的服务器数量。
下面将会介绍常见开发语言如果集成到Prometheus监控体系中。
Java
在Java世界里,所有应用事实上可以简单的划分为两类:Spring应用和非Spring应用。Spring已经成为了事实上的Jakarta EE(Java EE)标准,所以本节会分别介绍Spring应用和非Spring应用如何集成Prometheus指标。
Micrometer
首先需要说明一下就是Micrometer,Micrometer是一个在JVM-Based应用中的一个供应商中立的应用可观测性门面(facade),类似于slf4j。Micrometer支持常见的可观测性系统,包括Prometheus。
基本概念
Registry
每个应用都有一个MeterRegistry对象。是所有指标的注册表。
CompositeMeterRegistry
通过CompositeMeterRegistry,可以同时添加多个注册表,允许发布到多个监控系统
globalRegistry
一个静态全局注册表
Meter
监控中不同类型的指标,包括Timer
、Counter
、Gauge
、DistributionSummary
、LongTaskTimer
、FunctionCounter
、FunctionTimer
和TimeGauge
称作Meter。
命名约定
由于不同监控系统有不同的指标名约定,Micrometer建议使用小数点分割,然后会转换为目标监控系统推荐的命名约定,请看下面的例子:
1 | registry.timer("http.server.requests"); |
在不同的监控系统中,会转换为推荐的名称:
- Prometheus -
http_server_requests_duration_seconds
- Atlas -
httpServerRequests
- Graphite -
http.server.requests
- InfluxDB -
http_server_requests
SpringBoot & Micrometer
首先创建一个SpringBoot项目,然后添加依赖
1 | dependencies { |
接下来编辑application.yaml
,添加下面的配置:
1 | spring: |
首先,定义了应用的名称为JavaMetricsDemo
,然后在management中开启prometheus端点暴露,接下来通过mertris配置给所有指标添加了一个自定义tagapplication=JavaMetricsDemo
,方便区分
然后直接启动应用,访问http://localhost:8080/actuator/prometheus
,即可看到默认情况下会暴露一些常见指标,jvm,tomcat,logback等。
暴露自定义指标
在实际开发中,自带的指标肯定是不够用的,需要手动添加一些业务、接口相关指标,参考下面的代码:
1 |
|
我们创建了一个DemoController,然后定义了一个返回字符串的接口,注意我们在方法上面添加了**@Timed**注解,然后重新启动应用,观察指标变化
1 | # HELP http_server_requests_seconds |
由此我们可以知道,通过添加**@Timed**,可以获取接口响应时间相关指标,包含最大值,请求次数等。通过上述指标,可能会对服务健康提供一定帮助,也可以通过指标的tag精确到每个不同的接口请求。
接下来继续改造该类
1 |
|
通过IOC容器注入一个MeterRegistry,这就是上文说的每个应用的Registry对象,我们一般不需要手动创建,直接注入使用即可。
然后我们在init段中声明一个Counter类型的指标,这个过程建议单独放到一起,在应用启动时候注册到全局的Registry即可,然后我们获取一个叫foo.errors
的Counter,用来统计错误次数,每当程序发生异常,就将次数加一。
再次启动应用,手动请求几次接口,重新查看指标页面
1 | # HELP foo_errors_total Number of errors |
可以看到我们新增的指标已经添加上来了
指标名和代码中的不同?
这里按照micrometer约定,因为micrometer是一个厂商中立的api,所以为了保持统一性,代码中所有指标统一用点分隔,在具体的provider中会自动转换成目标推荐的格式,这里就按照Prometheus的格式转换成了下划线,又因为是counter类型,所以最后添加了_total后缀。
总之,在代码中统一使用点分隔即可
到这里,演示了如何使用micrometer在一个Java应用中暴露指标接口和自定义指标,其他类型参考Counter用法即可。
Prometheus client_java
偶然发现Prometheus官方提供的clinet库从之前的simple_client换成了client_java,并且释出了1.0版本,这里也简单使用一下
快速开始
详情参考 quickstart
首先引入依赖
1 | implementation 'io.prometheus:prometheus-metrics-core:1.0.0' |
prometheus-metrics-core
是指标库。prometheus-metrics-instrumentation-jvm
提供开箱即用的 JVM 指标。prometheus-metrics-exporter-httpserver
是一个用于公开 Prometheus 指标的独立 HTTP 服务器。
如果项目已经使用Servlet等,可以使用
prometheus-exporter-servlet-jakarta
代码示例
1 | import io.prometheus.metrics.core.metrics.Counter; |
这是首先初始化了prometheus-metrics-instrumentation-jvm
提供的自带的JVM指标,可以看到这里并没有Registry声明,因为通过这里可以看到client_java
默认隐式使用了一个全局的Registry,并且也推荐只使用默认实现。
然后通过CounterBuilder创建了一个Counter指标,并且设置了几个样本值,最后在9400端口启动了一个Prometheus指标端点。
分析源码可以发现
prometheus-metrics-exporter-httpserver
默认使用了jdk HttpServer实现
然后需要解释一下这里的labelNames
和labelValues
是怎么使用的,这里给出一个下面例子,相信看完你就懂了:
1 | Counter counter = Counter.builder() |
更多概念一文也无法讲清楚,若有需要推荐查看官网原文
Spring
目前client_java在2023年9月27日才发布1.0版本,所以目前官方还是推荐使用Micrometer方案。
非Spring项目中可考虑使用client_java和Micrometer皆可
其他语言
Prometheus提供了多种语言的SDK用来对应用可观测性指标收集,目前,官方支持的有:
非官方支持: