Prometheus的四大指标类型

Prometheus的四大指标类型

Prometheus有4大指标类型(Metrics Type),分别是Counter(计数器)、Gauge(仪表盘)、Histogram(直方图)和Summary(摘要)。

这是在Prometheus客户端(目前主要有Go、Java、Python、Ruby等语言版本)中提供的4种核心指标类型,但是Prometheus的服务端并不区分指标类型,而是简单地把这些指标统一视为无类型的时间序列。

注意:

<font color=red>上面这句话应该这么理解,四个指标类型,实际上就是客户端采集数据的四个维度,采集这四个维度的指标数据,但是最终汇总到服务端那里,则是对这四个维度无感的,只是简单的作为时间序列存储起来。</font>

Counter

 计数器表示一种单调递增的指标,除非发生重置的情况下下只增不减,其样本值应该是不断增大的。例如,可以使用Counter类型的指标来表示服务的请求数、已完成的任务数、错误发生的次数等。

 但是,计数器计算的总数对用户来说大多没有什么用,大家千万不要将计数器类型应用于样本数据非单调递增的指标上,比如当前运行的进程数量、当前登录的用户数量等应该使用仪表盘类型。

为了能够更直观地表示样本数据的变化情况,往往需要计算样本的增长速率,这时候通常使用PromQL的rate、topk、increase和irate等函数,如下所示:


rate(http_requests_total[5m]) // 通过rate()函数获取HTTP请求量的增长速率

topk(10, http_requests_total) // 查询当前系统中访问量排在前10的HTTP地址

如上所示,速率的输出rate(v range-vector)也应该用仪表盘来承接结果。

在上面的案例中,如果有一个标签是Device,那么在统计每台机器每秒接受的HTTP请求数时,可以用如下的例子进行操作。


sum without(device)(rate(http_requests_total[5m]))

补充

PromQL要先执行rate()再执行sum(),不能执行完sum()再执行rate()。

 这背后与rate()的实现方式有关,rate()在设计上假定对应的指标是一个计数器,也就是只有<font color=red>incr(增加)和reset(归零)</font>两种行为。而执行了sum()或其他聚合操作之后,得到的就不再是一个计数器了。举个例子,比如sum()的计算对象中有一个归零了,那整体的和会下降,而不是归零,这会影响rate()中判断reset(归零)的逻辑,从而导致错误的结果。

increase函数

 increase(v range-vector)函数传递的参数是一个区间向量,increase函数获取区间向量中的第一个和最后一个样本并返回其增长量。下面的例子可以查询Counter类型指标的增长速率,可以获取http_requests_total在最近5分钟内的平均样本,其中300代表300秒。


increase(http_requests_total[5m]) / 300

rate和increase函数的局限性

 rate和increase函数计算的增长速率容易陷入<font color=red>长尾效应中</font>。比如在某一个由于访问量或者其他问题导致CPU占用100%的情况中,通过计算在时间窗口内的平均增长速率是无法反映出该问题的

 为什么监控和性能测试中,我们更关注p95/p99位?就是因为长尾效应。由于个别请求的响应时间需要1秒或者更久,<font color=red>传统的响应时间的平均值就体现不出响应时间中的尖刺了</font>,去尖刺也是数据采集中一个很重要的工序,这就是所谓的长尾效应。p95/p99就是长尾效应的分割线,如表示99%的请求在XXX范围内,或者是1%的请求在XXX范围之外。99%是一个范围,意思是99%的请求在某一延迟内,剩下的1%就在延迟之外了。只是正推与逆推而已,是一种概念的两种不同描述。

 irate(v range-vector)是PromQL针对长尾效应专门提供的灵敏度更高的函数。irate同样用于计算区间向量的增长速率,但是其反映出的是瞬时增长速率。irate函数是通过区间向量中最后两个样本数据来计算区间向量的增长速率的。这种方式可以避免在时间窗口范围内的“长尾问题”,并且体现出更好的灵敏度。通过irate函数绘制的图标能够更好地反映样本数据的瞬时变化状态。irate的调用命令如下所示。


irate(http_requests_total[5m])

 irate函数相比于rate函数提供了更高的灵敏度,不过分析长期趋势时或者在告警规则中,irate的这种灵敏度反而容易造成干扰。因此,在长期趋势分析或者告警中更推荐使用rate函数。

Gauge

 仪表盘类型代表一种<font color=red>样本数据可以任意变化的指标,即可增可减</font>。它可以理解为状态的快照,Gauge通常用于表示温度或者内存使用率这种指标数据,也可以表示能随时增加或减少的“总数”,例如当前并发请求的数量node_memory_MemFree(主机当前空闲的内容大小)、node_memory_MemAvailable(可用内存大小)等。在使用Gauge时,用户往往希望使用它们<font color=red>求和、取平均值、最小值、最大值</font>等。

 以Prometheus经典的Node Exporter的指标node_filesystem_size_bytes为例,它可以报告从node_filesystem_size_bytes采集来的文件系统大小,包含device、fstype和mountpoint等标签。如果想要对每一台机器上的总文件系统大小求和(sum),可以使用如下PromQL语句。


sum without(device, fstype, mountpoint)(node_filesystem_size_bytes)

 without可以让sum指令根据相同的标签进行求和,但是忽略without涵盖的标签。如果在实际工作中需要忽略更多标签,可以根据实际情况在without里传递更多指标。


补充

node_filesystem_size_bytes指标查询

image.png

device, fstype, mountpoint都是他的标签。

sum without(device, fstype, mountpoint)(node_filesystem_size_bytes)查询

image.png

 如果要根据Node Exporter的指标node_filesystem_size_bytes计算每台机器上最大的文件安装系统大小,只需要将上述案例中的sum函数改为max函数,如下所示。


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小时内磁盘是否会满,如下所示:


predict_linear(node_filesystem_free[2h],24*3600)<0

image.png

PromQL还有一个内置函数delta(),它可以获取样本在一段时间内的变化情况,也通常作用于Gauge。例如,计算磁盘空间在2小时内的差异,如下所示。


delta(node_filesystem_free_bytes{}[2h])

image.png

Histogram

Histogram是一个对数据分布情况的图形表示,由一系列高度不等的长条图(bar)或线段表示,用于展示单个测度得知的分布。

  • 它一般用横轴表示某个指标维度的数据取值区间,用纵轴表示样本统计的频率或频数,从而能够以二维图的形式展现数值的分布状况

  • 为了构建Histogram,首先需要将值的范围进行分段,即将所有值的整个可用范围分成一系列连续、相邻(相邻处可以是等同值)但不重叠的间隔,而后统计每个间隔中有多少值。

  • 从统计学的角度看,分位数不能被聚合,也不能进行算术运算;

[图片上传失败...(image-3e55f2-1622153155462)]


上边界、样本值总和、样本总数

例子


prometheus_http_request_duration_seconds_bucket{handler="/targets",instance="192.168.16.134:9090",job="prometheus"}

prometheus_http_request_duration_seconds_count{handler="/targets",instance="192.168.16.134:9090",job="prometheus"}

prometheus_http_request_duration_seconds_sum{handler="/targets",instance="192.168.16.134:9090",job="prometheus"}


这三个查询一起看

上边界

image.png
  • 样本的值分布在Bucket中的数量,命名为<basename>_bucket{le="<上边界>"}。这个值表示指标值小于等于上边界的所有样本数量。上述案例中的prometheus_http_request_duration_seconds_bucket{handler="/targets",instance="192.168.16.134:9090",job="prometheus",le="0.1"}12 就代表在总共的11次请求中,HTTP请求响应时间≤0.1s的请求一共是11次。

样本值总和

image.png

所有样本值的总和,命名为<basename>_sum。

prometheus_http_request_duration_seconds_sum{handler="/targets",instance="192.168.16.134:9090",job="prometheus"}0.405075955 表示12 次http请求的总响应时间是0.405075955

样本总数

命名为<basename>_count,其值和<basename>_bucket{le="+Inf"}相同(所有)。


image.png

prometheus_http_request_duration_seconds_count{handler="/targets",instance="192.168.16.134:9090",job="prometheus"}12 表示总共发生了12次请求


 sum函数和count函数相除,可以得到一些平均值,比如Prometheus一天内的平均压缩时间,可由查询结果除以instance标签数量得到,如下所示。


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两个指标得到的,是一个近似值)。

例子如下。


histogram_quantile(0.1, prometheus_http_request_duration_seconds_bucket)

Summary

 与Histogram类型类似,摘要用于表示一段时间内的数据采样的结果(通常是请求持续时间或响应大小等),但它直接存储了分位数(通过客户端计算,然后展示出来),而非通过区间来计算(Histogram的分位数需要通过histogram_quantile(φfloat,b instant-vector)函数计算得到)。因此,对于分位数的计算,Summary在通过PromQL进行查询时有更好的性能表现,而Histogram则会消耗更多的资源。反之,对于客户端而言,Histogram消耗的资源更少。在选择这两种方式时,用户应该根据自己的实际场景选择。

Histogram是在服务端计算的,Summary是在客户端计算的。

 安装并启动Prometheus后,在访问http://localhost:9090/metrics时可以看到Prometheus自带的一些Summary信息,这些信息和Histogram一样在注释中(#HELP和#TYPE)也会显示,如下所示。


# 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种指标,假设指标名称为<basename>。

  • 样本值的分位数分布情况,命名为<basename>{quantile="<φ>"},属于计数器类型。

  • 所有样本值的大小总和,命名为<basenamesum,属于计数器类型。

  • 样本总数,命名为<basename>_count,属于计数器类型。

Summary和Histogram的异同

  • 它们都包含了<basename>_sum和<basename>_count指标。

  • Histogram需要通过<basename_bucket来计算分位数,而Summary则直接存储了分位数的值。

  • 如果需要汇总或者了解要观察的值的范围和分布,建议使用Histogram;如果并不在乎要观察的值的范围和分布,仅需要精确的quantile值,那么建议使用Summary。

Summary的强大之处就是可以利用除法去计算时间的平均值。如果要从Histogram和Summary中计算最近5分钟内的平均请求持续时间http_request_duration_seconds,可以用如下表达式进行。


rate(http_request_duration_seconds_sum[5m])/rate(http_request_duration_seconds_

    count[5m])

count本质上是一个计数器,sum通常情况下也会像计数器那样工作。但是<font color=red>Summary和Histogram可能观察到负值,比如温度(-20℃),这种情况下会导致观察的总量下降,无法再使用rate函数</font>。

比如下面的例子就可以计算过去5分钟内每次响应中返回的平均字节数。


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"})

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容