go 自定义metric

简介

Prometheus是一个开源监控系统,在除了纯数字时间序列方面表现非常好。它既适用于面向服务器等硬件指标的监控,也适用于高动态的面向服务架构的监控。对于现在流行的微服务,Prometheus的多维度数据收集和数据筛选查询语言也是非常的强大。

Prometheus的主要特性包括:

  1. 多维度数据模型

  2. 灵活的查询语言

  3. 不依赖分布式存储,单个服务器节点是自治的

  4. 通过服务(sd,准确的说是监控目标)发现或者静态配置,来发现目标服务对象

  5. 支持多种多样的图表和界面展示,可以和Grafana集成

  6. 数据采集方式:

    1. Pull:通过HTTP协议定期去采集指标,只要被监控系统提供HTTP接口即可接入

    2. Push:被监控系统主动推送指标到网关,Prometheus定期从网关Pull

Prometheus包括以下组件:

  1. Prometheus Server:负责抓取和存储时间序列数据

  2. Push Gateway:推送网关,第三方可以推送数据到此网关,Prometheus Server再从此网关拉取数据

  3. 多种导出工具,支持导出Graphite、StatsD等所需的格式

  4. 命令行查询工具

  5. Alert Manager:告警管理器

  6. PromQL查询语言

架构图

数据模型

Prometheus中所有数据都存放为时间序列——具有时间戳的数据流,这些数据属于同一指标、以及由一系列标签定义的维度集。每个时间序列由指标名+标签集唯一的识别,标签由键、值组成。时间序列通常使用如下记号表示:

指标名是需要监控系统特性的一般性名称,例如http_requests_total可以表示HTTP请求计数。

标签为一个具体的指标“实例”提供维度信息。使用PromQL你可以基于标签进行过滤、分组。增加、修改、删除某个标签,则新的时间序列会被创建。标签名只能ASCII字符,但是标签值可以是任何Unicode字符。

样本(Sample)构成了实际的时间序列的数据点。样本由float64类型的数值+毫秒精度的时间戳组成。指标类型

Prometheus的客户端库区分了4种指标类型,目前服务器端不理解这些类型的不同,但是未来可能改变。

Job和实例

一个你可以从中抓取监控数据的endpoint称为实例(Instance),实例通常对应一个进程,例如NodeExporter、RedisExporter……

一系列相同目的的实例,称为Job。多实例的原因可能是为了可靠性、扩容。

当Prometheus服务器抓取数据时,它会自动为时间序列添加标签:

  1. job,抓取目标所属的Job的名称

  2. instance,目标从什么host:port抓取得到

如果上述两个标签已经存在于抓取的数据上,则配置项honor_labels影响服务器的行为。

除了添加标签之外,还会为以下时间序列添加样本:

  1. up{job="<job-name>", instance="<instance-id>"}:1/0。如果实例可达则取值1,否则0

  2. scrape_duration_seconds{job="<job-name>", instance="<instance-id>"}:抓取目标消耗的时间

  3. scrape_samples_post_metric_relabeling{job="<job-name>", instance="<instance-id>"}:指标重打标签后,剩余的样本数量

  4. scrape_samples_scraped{job="<job-name>", instance="<instance-id>"}: 目标暴露的样本数量

对比其它TSDBGraphite

Graphite专注于作为一个被动的时间序列数据库,同时提供查询语言、图形化特性。Prometheus则是一个全功能的监控和趋势分析系统,内置主动拉取、存储、图形化、报警功能。

Graphite存储数字采样,但是其元数据模型不如Prometheus丰富。Graphite的指标名称使用点号分隔的单词,暗含维度信息。Prometheus则将维度信息作为明确的标签存储。Prometheus更容易支持过滤、分组操作。

Graphite在本地磁盘上,以Whisper格式存储时间序列数据。每个时间序列存储一个文件,一段时间后,新采样会覆盖旧采样,此外采样频率是固定的。Prometheus也是每个时间序列对应一个文件,但是采样频率是动态的,新数据简单的Append到文件尾部。InfluxDB

InfluxDB的持续查询类似于Prometheus的Recording规则。Kapacitor类似于Recording规则、Alerting规则和Alertmanager的通知功能的组合。Alertmanager具有额外的分组、去重、静默功能。

InfluxDB的Tag和Prometheus的Label一样,都是键值对形式的维度信息。InfluxDB还提供第二级的“标签”——字段(Field)术语

安装K8SShell

此Chart的定义位于:https://github.com/gmemcc/charts/tree/master/prometheus

安装完毕,到https://prometheus.k8s.gmem.cc/targets可以查看各监控目标的状态。StandaloneShell

配置

Prometheus通过命令行、配置文件进行配置。命令行参数可以配置一些不变的系统参数,例如存储位置、存留在内存和磁盘中的数据量。配置文件则用于指定Job、Instance、Rule的配置。配置文件

配置文件的格式是YAML,使用--config.file指定配置文件的位置。本节列出重要的配置项。全局配置Shell

scrape_config

配置一系列的目标,以及如何抓取它们的参数。一般情况下,每个scrape_config对应单个Job。

目标可以在scrape_config中静态的配置,也可以使用某种服务发现机制动态发现。Shell

kubernetes_sd_config

使用该配置,可以从K8S API Server暴露的REST API中发现抓取目标,并且和K8S集群保持同步。你可以配置以下role,以发现目标:

通常,你会给相关K8S资源添加以下注解:YAML

并配合以下Relabel配置,提示这些资源需要作为Prometheus的抓取目标:YAML

relabel_config

重打标签是动态修改目标的标签集的强大工具。每个抓取配置可以定义多个重打标签步骤,这些步骤按照声明顺序依次执行、在实际抓取指标数据之前执行。

在一开始,除了为每个目标配置的标签之外,目标的:

  1. job标签被设置为抓取配置的job_name字段

  2. __address__标签被设置为目标的<host>:<port>

在重打标签之后,目标的:

  1. instance标签默认被设置为__address__,如果没有此标签的话

  2. __scheme__标签被设置为http或https

  3. __metrics_path__标签被设置为目标的指标路径,即URL路径

  4. __param_<name>标签为请求时使用的每个参数

在重打标签期间,额外的 __meta_ 开头的元标签可用,这些标签由服务发现机制自动添加。

在重打标签结束后,以__开头的标签会被移除。

如果某个步骤需要临时的设置一些标签,仅仅作为后续步骤的输入,应当以__tmp作为前缀。

每个重打标签步骤(relabel_configs的元素)具有以下子配置项:Shell

重打标签配置示例:YAML

metric_relabel_configs

在存储(ingestion)样本数据之前,作为最后一个步骤,配置同上。可以用于屏蔽存储成本过高的时间序列。配置文件示例默认配置文件

Prometheus使用YAML格式的配置文件,默认的配置文件内容如下:YAML

PromQL

Prometheus提供了一种查询语言,用来实时的查询、聚合时间序列数据。查询结果可以在Prometheus的WebUI中展示,或者通过HTTP API暴露给第三方系统。语法示例Shell

数据类型

语法瞬时矢量选择器

匹配单个时间点的一个或多个时间序列的采样:Shell

匹配标签时可以使用四种操作符:=、!=、=~、!~,前两者用于精确匹配,后两者用于正则式匹配:Shell

范围矢量选择器

只需要在瞬时矢量选择器后面添加 [timePeriod] 即可,时间的单位可以是s、m、h、d、w、y。示例:Shell

偏移量修饰符Shell

操作符

算术:加减乘除、取模、乘方(^)。可以在两个标量、标量vs瞬时矢量、 两个瞬时矢量之间进行。

比较:== != > >= < <=。可以在两个标量、标量vs瞬时矢量、 两个瞬时矢量之间进行。

逻辑:and or unless。仅仅用于两个瞬时矢量之间:

  1. and,取v1 v2中具有完全一致Label的那些时间序列,构成v3返回

  2. or,取v1所有时间序列,外加v2中那些Label在v1中不存在的时间序列,构成v3返回

  3. unless,取v1中那些没有在v2中具有相同Label的时间序列

矢量匹配

对两个瞬时矢量应用操作符时,牵涉到如何找到左侧矢量元素在右侧矢量中的匹配元素的问题。匹配都是基于Label的。

矢量匹配的行为有两种:1对1匹配,1对多匹配:

聚合操作符

操作符列表:

语法:Shell

函数

注意点先rate再sum

不能对已经聚合过的数据再进行rate,只能对原始counter进行rate。正确的示例:SQL

集成K8S安装

这里使用Helm Chart方式安装,Chart的源码位于:

https://git.gmem.cc/alex/helm-charts/src/branch/master/prometheus

安装脚本如下:Shell

说明

上面的Chart默认配置了以下Job:

指标采集自我监控

启动Prometheus后,访问http://localhost:9090/metrics可以查看Prometheus本身的指标信息:Shell

http_requests_total是Prometheus暴露(Export)的关于自身的指标 —— 接受的HTTP请求总数,包括了多个时间序列数据。这些时间序列数据的指标名都一样,但是具有不同的标签,这些标签用于区分不同类型的HTTP请求。

我们可以在控制台输入 http_requests_total{code="200"},表示仅仅查询具有标签code=200的HTTP请求数。

类似的,还可以使用表达式 count(http_requests_total),来统计指标http_requests_total具有的时间序列数据的数量。

在http://localhost:9090/graph页面,点击Graph选项卡,可以生成图表。例如表达式 rate(http_requests_total[1m]) 表示生成最近一分钟的HTTP请求总数的图表,每个时间序列产生一条曲线。Node Exporter

Node Exporter是Prometheus提供的,用于监控Linux系统的组件。对于Windows,则有功能类似的WMIExporter

下载NodeExporter后运行,它默认会在9100端口上暴露本机的各项指标。你可以访问http://localhost:9100/metrics来查看。修改Prometheus默认配置文件尾部的9090端口为9100即可采集这些指标。cAdvisor

这个项目是Google开源的,专门采集容器资源用量、性能指标。cAdvisor嵌入在kubelet中运行。JMX Exporter

此项目可以暴露JMX管理Beans给Prometheus采集。它作为Java Agent运行,开启一个HTTP端口,对外提供本地JVM的各项指标。

为JVM添加参数: -javaagent:jmx_prometheus_javaagent-0.3.1.jar=9100:config.yaml即可运行此Exporter。其中9100为暴露的端口号,config.yaml为配置文件路径。要采集指标,访问http://host:9100/metrics即可。配置文件

格式为YAML:YAML

如果没有任何配置内容,则以默认格式采集本地JVM的所有指标。

官方提供了若干中间件的示例配置文件。 输入pattern

传递给配置文件rules.pattern的格式为:Shell

不经配置,输出的默认指标格式为:Shell

客户端编程

Prometheus提供了主流语言的客户端库。要使用Prometheus的Go客户端库,导入:Go

核心类型Desc

该结构是任何Prometheus指标都需要使用的描述符,它本质上是指标(Metrics)的不可变元数据:Go

Metric

所有指标的通用接口,表示需要导出到Prometheus的单个采样值+关联的元数据集 。此接口的实现包括Gauge、Counter、Histogram、Summary、Untyped。Go

MetricVec

此结构表示用于bundle全限定名称、标签值有所不同的指标。通常不会直接使用此结构,而是将它作为具体指标向量GaugeVec, CounterVec, SummaryVec, UntypedVec的一部分:Go

Opts

创建大部分的指标类型时,可以通过该接口提供选项:Go

Collector

任何Prometheus用来收集指标的对象,都需要实现此接口:Go

收集器必须被注册(Registerer.Register)才能收集指标值。

内置的指标类型实现了此接口,包括GaugeVec、CounterVec、HistogramVec、SummaryVec。Registry

注册表,此结构实现了Registerer、Gatherer接口。

Registerer接口为注册表提供注册/反注册功能:Go

Gatherer为注册表提供汇集(gathering)功能 —— 将已经收集的指标汇集到若干指标族(MetricFamily)中:Go

Gauge

表示gauge类型的指标: Go

要创建一个Gauge,可以调用:Go

GaugeVec表示Gauge的向量:Go

Histogram

表示histogram类型的指标。

Histogram对可配置的Bucket(观察值的区间)中的事件或样本流,基于Bucket进行独立计数观察。它支持对观察值(observations)进行计数,或者求和。

在Prometheus中,分位数可以基于Histogram,通过函数histogram_quantile计算得到。Histogram依赖于用户定义的、适当的buckets,一般来说精确度相对较低,但是和Summary比起来,Histogram的性能成本较低。Go

默认的Buckets如下,主要用于测量网络响应延迟的场景:Go

对于其它场景,你应当自己定义Buckets。 创建指标

我们不会直接操控指标,而是使用它们的向量 —— GaugeVec、CounterVec、HistogramVec、SummaryVec。这些向量都是Collector接口的实现。

要创建向量,需要调用prometheus.New***Vec方法,例如:Go

Gauge

下面的例子创建一个Gauge向量:Go

获取具有指定标签值的Gauge(时间序列): Go

产生一个指标值:Go

Histogram

下面的例子使用默认Bucket创建Histogram向量:Go

产生一个指标值:Go

注册指标默认注册表

Prometheus客户端提供了开箱即用的默认注册表: prometheus.DefaultRegisterer创建注册表

你可以调用以下函数来创建注册表:Go

示例:Go

注册收集器 Go

暴露指标

Prometheus客户端不能直接将指标发送给Prometheus服务器。只能通过网络端口暴露一个Exporter。

如果要基于HTTP协议暴露,将promhttp包提供的Handler传递给你的HTTP服务器,每个Handler读取单个注册表,从中收集指标信息,生成HTTP响应:Go

如果你需要使用非默认注册表,直接调用:Go

然后将Handler传递给你的ServeMux即可:Go

Last updated