Prometheus的四大指标类型
Prometheus有4大指标类型(Metrics Type),分别是Counter(计数器)、Gauge(仪表盘)、Histogram(直方图)和Summary(摘要)。
这是在Prometheus客户端(目前主要有Go、Java、Python、Ruby等语言版本)中提供的4种核心指标类型,但是Prometheus的服务端并不区分指标类型,而是简单地把这些指标统一视为无类型的时间序列。
注意:
上面这句话应该这么理解,四个指标类型,实际上就是客户端采集数据的四个维度,采集这四个维度的指标数据,但是最终汇总到服务端那里,则是对这四个维度无感的,只是简单的作为时间序列存储起来。
Counter
?计数器表示一种单调递增的指标,除非发生重置的情况下下只增不减,其样本值应该是不断增大的。例如,可以使用Counter类型的指标来表示服务的请求数、已完成的任务数、错误发生的次数等。
?但是,计数器计算的总数对用户来说大多没有什么用,大家千万不要将计数器类型应用于样本数据非单调递增的指标上,比如当前运行的进程数量、当前登录的用户数量等应该使用仪表盘类型。
为了能够更直观地表示样本数据的变化情况,往往需要计算样本的增长速率,这时候通常使用PromQL的rate、topk、increase和irate等函数,如下所示:
sum without(device)(rate(http_requests_total[5m]))
补充
PromQL要先执行rate()再执行sum(),不能执行完sum()再执行rate()。
?这背后与rate()的实现方式有关,rate()在设计上假定对应的指标是一个计数器,也就是只有incr(增加)和reset(归零)两种行为。而执行了sum()或其他聚合操作之后,得到的就不再是一个计数器了。举个例子,比如sum()的计算对象中有一个归零了,那整体的和会下降,而不是归零,这会影响rate()中判断reset(归零)的逻辑,从而导致错误的结果。
increase函数
?increase(v range-vector)函数传递的参数是一个区间向量,increase函数获取区间向量中的第一个和最后一个样本并返回其增长量。下面的例子可以查询Counter类型指标的增长速率,可以获取http_requests_total在最近5分钟内的平均样本,其中300代表300秒。
irate(http_requests_total[5m])
?irate函数相比于rate函数提供了更高的灵敏度,不过分析长期趋势时或者在告警规则中,irate的这种灵敏度反而容易造成干扰。因此,在长期趋势分析或者告警中更推荐使用rate函数。
Gauge
?仪表盘类型代表一种样本数据可以任意变化的指标,即可增可减。它可以理解为状态的快照,Gauge通常用于表示温度或者内存使用率这种指标数据,也可以表示能随时增加或减少的“总数”,例如当前并发请求的数量node_memory_MemFree(主机当前空闲的内容大小)、node_memory_MemAvailable(可用内存大小)等。在使用Gauge时,用户往往希望使用它们求和、取平均值、最小值、最大值等。
?以Prometheus经典的Node Exporter的指标node_filesystem_size_bytes为例,它可以报告从node_filesystem_size_bytes采集来的文件系统大小,包含device、fstype和mountpoint等标签。如果想要对每一台机器上的总文件系统大小求和(sum),可以使用如下PromQL语句。
max without(device, fstype, mountpoint)(node_filesystem_size_bytes)
image.png
?除了求和、求最大值等,利用Gauge的函数求最小值和平均值等原理是类似的。除了基本的操作外,Gauge经常结合PromQL的predict_linear和delta函数使用。
?predict_linear(v range-vector,t scalar)函数可以预测时间序列v在t秒后的值,就是使用线性回归的方式,预测样本数据的Gauge变化趋势。例如,基于2小时的样本数据,预测未来24小时内磁盘是否会满,如下所示:
delta(node_filesystem_free_bytes{}[2h])
image.png
Histogram
Histogram是一个对数据分布情况的图形表示,由一系列高度不等的长条图(bar)或线段表示,用于展示单个测度得知的分布。
-
它一般用横轴表示某个指标维度的数据取值区间,用纵轴表示样本统计的频率或频数,从而能够以二维图的形式展现数值的分布状况
-
为了构建Histogram,首先需要将值的范围进行分段,即将所有值的整个可用范围分成一系列连续、相邻(相邻处可以是等同值)但不重叠的间隔,而后统计每个间隔中有多少值。
-
从统计学的角度看,分位数不能被聚合,也不能进行算术运算;
[图片上传失败...(image-3e55f2-1622153155462)]
上边界、样本值总和、样本总数
例子
sum without(instance)(rate(prometheus_tsdb_compaction_duration_sum[1d]))
/
sum without(instance)(rate(prometheus_tsdb_compaction_duration_count[1d]))
?除了Prometheus内置的压缩时间,prometheus_local_storage_series_chunks_persisted表示Prometheus中每个时序需要存储的chunk数量,也可以用于计算待持久化的数据的分位数。
?Histogram可以用于观察样本数据的分布情况。Histogram的分位数计算需要通过histogram_quantile(φfloat,b instant-vector)函数进行计算,但是histogram_quantile计算所得并非精确值。其中,φ(0<φ<1)表示需要计算的分位数(这个值主要是通过prometheus_http_request_duration_seconds_bucket和prometheus_http_request_duration_seconds_sum两个指标得到的,是一个近似值)。
例子如下。
# HELP go_gc_duration_seconds A summary of the GC invocation durations.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 1.1666e-05
go_gc_duration_seconds{quantile="0.25"} 2.6265e-05
go_gc_duration_seconds{quantile="0.5"} 4.8366e-05
go_gc_duration_seconds{quantile="0.75"} 7.8298e-05
go_gc_duration_seconds{quantile="1"} 0.000280123
go_gc_duration_seconds_sum 0.193642882
go_gc_duration_seconds_count 1907
?在上述例子中,可以看到基于Go语言编写的Prometheus的gc总次数是1907,耗时0.193642882s,其中中位数(quantile=0.5)计算的耗时为4.8366e-05s,代表1907次中50%的次数是小于4.8366e-05s的。
Summary类型的样本也会提供3种指标,假设指标名称为
-
样本值的分位数分布情况,命名为
{quantile="<φ>"},属于计数器类型。 -
所有样本值的大小总和,命名为
-
样本总数,命名为
_count,属于计数器类型。
Summary和Histogram的异同
-
它们都包含了
_sum和 _count指标。 -
Histogram需要通过
-
如果需要汇总或者了解要观察的值的范围和分布,建议使用Histogram;如果并不在乎要观察的值的范围和分布,仅需要精确的quantile值,那么建议使用Summary。
Summary的强大之处就是可以利用除法去计算时间的平均值。如果要从Histogram和Summary中计算最近5分钟内的平均请求持续时间http_request_duration_seconds,可以用如下表达式进行。
sum without(handler)(rate(http_response_size_bytes_sum[5m]))
/
sum without(handler)(rate(http_response_size_bytes_count[5m]))
关于这个例子,我们需要注意几点。
·因为http_response_size_bytes_count和http_response_size_bytes_sum是计数器类型,所以必须在计算前先使用rate等函数。
·因为Prometheus的API会有很多handler,所以可以使用without过滤掉handler的返回值。
·PromQL要先执行rate()再执行sum(),不能先执行sum()再执行rate()。
·在统计学上,尤其是计算平均值时,要先进行sum等求和运算再做除法。对一个平均值再求平均是不正确的,如下所示。
// 合法
sum without(instance)(
sum without(handler)(rate(http_response_size_bytes_sum[5m]))
)
/
sum without(instance)(
sum without(handler)(rate(http_response_size_bytes_count[5m]))
)
// 非法
avg without(instance)(
sum without(handler)(rate(http_response_size_bytes_sum[5m]))
/
sum without(handler)(rate(http_response_size_bytes_count[5m]))
)
// 非法
avg(http_request_duration_seconds{quantile="0.95"})
count的例子
案例一:计算所有的实例CPU核心数。
count by (instance) ( count by (instance,cpu) (node_cpu_seconds_total{mode=
"system"}) )
案例二:计算单个实例192.168.1.1的CPU核心数。
count by (instance) ( count by (instance,cpu) (node_cpu_seconds_total{mode="system",
instance="192.168.1.1"})
作者:乙腾
链接:https://www.jianshu.com/p/a3b74ad9b7be
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。