Prometheus采集监控指标的方式如下图所示,Prometheus Server经过一定的配置可以从各种Exporter主动采集监控数据。广义上的Exporter可以是任何以Prometheus标准暴露监控指标的进程。不过严格来说可以划分为以下两类:
1. 对于Etcd这类应用程序,它们在代码中利用Prometheus官方提供的SDK定义了一系列自定义指标供Prometheus Server采集,此类指标一般用于描述该程序自身的运行状况。一般对于新开发或者改动难度较小的程序,可以用这种对代码侵入性较大的方式暴露指标。 2. 标准意义上的Expoerter本质上就是指标的转换层,例如Prometheus社区提供了一个名为Node Exporter的组件,该组件的作用为采集节点的CPU,内存等指标并转换以符合Prometheus标准的格式暴露出去。一般对于代码改动难度较大或已经有成熟的指标暴露机制的程序,这种方式是较为合适的。Prometheus Server采集指标的方式,本质上是向Exporter发送一个HTTP请求并获取该Exporter定义的所有指标内容,例如对于Node Expoerter的采集形式如下:
# curl http://192.168.0.6:9100/metrics # HELP node_network_transmit_bytes_total Network device statistic transmit_bytes. # TYPE node_network_transmit_bytes_total counter node_network_transmit_bytes_total{device="eth0"} 2.74314960472e+11 node_network_transmit_bytes_total{device="lo"} 7.248889467e+09 # HELP node_boot_time_seconds Node boot time, in unixtime. # TYPE node_boot_time_seconds gauge node_boot_time_seconds 1.574417622e+09 ...
从上述示例可以看到,一次抓取过程返回的内容本质上是纯文本,我们截取了其中的两个指标,`node_network_transmit_bytes_total`和`node_boot_time_seconds`分别表示节点上各个网卡发送的数据的字节数以及节点的启动时间。对于`node_network_transmit_bytes_total`包含一个key为`device`的label用于区分各个网卡,而`node_boot_time_seconds`并不包含任何指标。 事实上,指标中包含的label能够让我们从更多维度更好地对指标进行操作。但是很多时候,Exporter指标中原生定义的label是不足以满足我们的需求的。例如,对于Node Exporter暴露的指标中显然没有包含组织信息的label,但是如果有这么一个label存在,加上Prometheus强大的PromQL查询语句,我们能够很容易地从组织维度对指标进行划分。 那么如何在Exporter暴露的指标中添加额外的label呢?最直接的方式当然是侵入式地修改Exporter的源码,从而在源头加上这些“定制化”的labels。当然,这种方式对于一些简单的自研组件是可行的。但是对于Node Exporter以及Nginx Exporter等较为复杂的Exporter直接修改源码并不是那么地简单,而且假如我要为所有指标加上一个公共的label,那么也就意味着要修改所有Exporter的源码。 显然,我们需要一种更为通用的方式,从上文的分析可知,标准意义的Exporter本质上是一个中间层,用于指标的转换。那么我们是否可以再加一个中间层,用于自定义label的添加呢?架构如下: 在Prometheus Server和Exporter之间构建一个中间组件Adapter,此时Prometheus不再直接向Exporter发起HTTP请求抓取监控指标,而是向Adapter发起请求。一旦Adapter接收到请求之后会转而向Exporter发起请求真正抓取到监控指标。已知指标内容其实就是一些文本,因此只要做一些简单的插入操作就能将自定义的指标注入。最后,将处理后的内容再返回至Prometheus Server即可。若Adapter注入的指标为{org="dev"},那么经过Adapter处理之后,Prometheus Server真正抓取到的指标如下:
# curl http://192.168.0.6:9100/metrics # HELP node_network_transmit_bytes_total Network device statistic transmit_bytes. # TYPE node_network_transmit_bytes_total counter node_network_transmit_bytes_total{device="eth0", org="dev"} 2.74314960472e+11 node_network_transmit_bytes_total{device="lo", org="dev"} 7.248889467e+09 # HELP node_boot_time_seconds Node boot time, in unixtime. # TYPE node_boot_time_seconds gauge node_boot_time_seconds{org="dev"} 1.574417622e+09 ...
通常在Kubernetes环境下,我们会将Adapter以Sidecar的形式部署在Exporter所在的Pod中,如果能够将Adapter需要注入的指标值从配置文件中读取并支持动态加载机制,那么我们就能非常灵活地为任意Exporter的指标加入任意的定制化label。