为什么Prometheus既有计数器又有测量值,如果测量值可以充当计数器?

33
在选择 CounterGauge 时,Prometheus文档指出

在选择计数器和仪表的情况下,有一个简单的经验法则: 如果值可能会降低,则使用仪表。计数器只能增加(并重置,例如当进程重新启动时)。

它们似乎覆盖了相互重叠的用例:您可以使用仅增加的 Gauge。那么为什么要在第一次创建 Counter 指标类型?为什么不仅使用 Gauges?

4个回答

36

从概念上来看,计量表和计数器有不同的目的。

  • 计量表通常表示状态,通常用于检测饱和状态。
  • 计数器的绝对值并不真正有意义,真正的目的是使用类似于 irate/rate(), increase() 等函数来计算演变(通常是利用率)。

这些增长操作需要可靠地计算增长,而您无法通过计量表来实现,因为您需要检测值的重置。

技术上,计数器具有两个重要属性:

  1. 它始终从 0 开始。
  2. 它总是在增加(即在代码中增加)。

如果应用程序在两次 Prometheus 抓取之间重新启动,则第二次抓取的值可能会少于前一次抓取的值,并且可以恢复增加(有点损失,因为您将始终损失最后一次抓取和重置之间的增加量)。

计算从 t1 到 t2 的计数器增量的简单算法是:

  • 如果 counter(t2) >= counter(t1),则 increase=counter(t2)-counter(t1)
  • 如果 counter(t2) < counter(t1),则 increase=counter(t2)

总之,从技术角度来看,您可以使用计量表而不是计数器,只要在启动时将其重置为0并仅对其进行递增,但任何违反合同的行为都会导致错误值。

另外,我也希望计数器实现使用无符号整数表示,而计量表则使用浮点表示。这对代码有一些微小的影响,例如能够自动溢出为0以及更好地支持当前CPU上的原子操作。


1
谢谢您的回复。让我来解释一下您的回答,看看我是否理解正确。Prometheus并不关心我们发送哪种类型的指标。我们选择CounterGauge取决于我们如何使用指标,这样我们就可以假定某些属性。就像我们在编程时使用私有方法一样:从技术上讲,它不必是私有的,但我们这样做是为了帮助其他人思考代码。我们还可以说,当我们想要聚合其值时,应该使用Counter吗?我们不会添加CPU使用情况(即Gauge),但我们可能想要添加总请求数。 - Jose Armesto
2
没错。我想补充一下,Textfile格式暴露了类型信息。例如:# TYPE http_requests_total counter。这有助于发现暴露的指标或进行健全性检查时进行仪表化。 - Michael Doubez
“我们能否说当我们想要聚合其值时,应该使用Counter?” - 不行,根据指标的含义和您想要获得的结果,您将使用不同的聚合函数(平均值/最小值/最大值/等等)。文档中给出的经验法则是明智的。 - Michael Doubez

9

对此的敏锐观察是:

Gauge的感觉是:

仅当度量的SUM操作在任何时间间隔内都没有意义时,Gauge才是适当的

例如,如果哈勃太空望远镜正在观察其天体扫描中观测到的每颗星星的亮度 - 温度的总和 - 不会产生任何有价值的信息。

同样地对于银行余额。每天您的银行余额的总和不是财富的有意义指标。因此,请使用Gauge进行平均间隔。


rate() 函数问题只是与rate()函数比与Gauge和Counter技术上的细微差别。

罪魁祸首是rate()在检测重置方面过于聪明。似乎没有数学原因说明为什么不能在Gauge中进行simple-rate()


6

对于计数器,您关心它的增长速度,而对于仪表,您关心实际值。虽然有些仪表理论上只会上升,但这并不意味着它们是计数器。


如果我两个都关心怎么办? - trallnag

1
在您的应用程序中,通常使用Prometheus客户端库,但您也可以自己跟踪指标并将其导出到自己的http-metrics-endpoint。
假设我们制作了一个正在处理某些内容的应用程序,并且您想要导出有关已处理的对象总数的一个指标(自应用程序启动以来)。另一个指标可能是当前有多少个线程正在处理某些内容。这两个都是我们可以通过http-metrics-endpoint导出到Prometheus的整数。看起来像这样:
myapp_processed_total 23
myapp_processing_current_threads 8

由于我们知道第一个myapp_processed_total仅向上计数,因此我们可能希望将其声明为计数器。第二个myapp_processing_current_threads可以上下移动,以指示当前正在使用多少线程。我们可能希望将其声明为测量器。

在我们的http-metrics-endpoint上,这些只是带有#TYPE:的“注释”或注释。

# TYPE myapp_processed_total counter
myapp_processed_total 23
# TYPE myapp_processing_current_threads gauge
myapp_processing_current_threads 8

Prometheus或者另一个管理员可以使用这些信息来创建有意义的仪表板,通过鼠标悬停读取注释,在计数器上使用rate()-函数进行查询,但不能在测量仪上使用。如果您从头开始制作指标,两者都只是数字。但是,为了进一步使用您的指标,添加#TYPE信息(以及#HELP信息)肯定是一个好习惯。

子结果可以使用花括号中的标签/键值标记定义。例如,当我们想要区分成功处理的对象数量和由于错误而被处理和中止的对象数量时,我们可能想要做类似于这样的事情:

# HELP myapp_processed_total some useful information here
# TYPE myapp_processed_total counter
myapp_processed_total{status="success"} 20
myapp_processed_total{status="failure"} 3

另一个管理员可能会在您的指标数据上创建有意义的仪表板和查询。

总结一下:

  • 是的,计数器和仪表都只是应用程序中的数字
  • 但指定类型有助于进一步处理您的度量标准
  • 可以使用现有的Prometheus客户端库

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接