常见问题

一般问题

Prometheus是什么:

Prometheus是一款高活跃生态系统的开源系统监控和警告工具包。详见概览

Prometheus与其他的监控系统比较:

详见比较

Prometheus有什么依赖:

Prometheus服务独立运行,没有其他依赖

Prometheus有高可用的保证吗:

是的,在多台服务器上运行相同的Prometheus服务,相同的报警会由警告管理器删除
警告管理器当前不能保证高可用,但高可用是目标

我被告知Prometheus"不能水平扩展":

事实上,有许多方式可以扩展Prometheus。阅读Robust Percetion的博客关于Prometheus的扩展

在通常的设置中,不可能使用inode。有一个可能的缺点:如果你想删除Prometheus的存储目录,你会注意到,一些文件系统在删除文件时非常慢。

为什么Prometheus服务器组件不支持TLS或身份验证?我可以添加这些吗?

虽然TLS和身份验证是经常请求的功能,但我们有意不在Prometheus的任何服务器端组件中实现它们。 有这么多不同的选项和参数(仅限TLS的10多个选项),我们决定专注于建立最佳的监控系统,而不是在每个服务器组件中支持完全通用的TLS和身份验证解决方案。

如果您需要TLS或身份验证,我们建议将反向代理放在Prometheus前面。参见例如使用Nginx添加对Prometheus的基本认证。

请注意,这仅适用于入站连接。Prometheus确实支持删除TLS-和auth启用的目标,以及其他创建出站连接的Prometheus组件具有类似的支持。


概念

数据模型

Prometheus从根本上存储的所有数据都是时间序列:具有时间戳的数据流只属于单个度量指标和该度量指标下的多个标签维度。

除了存储时间序列数据外,Prometheus也可以利用查询表达式存储5分钟的返回结果中的时间序列数据。

metrics和labels(度量指标名称和标签)

每一个时间序列数据由metric度量指标名称和它的标签labels键值对集合唯一确定。

这个metric度量指标名称指定监控目标系统的测量特征(如:http_requests_total- 接收http请求的总计数)。metric度量指标命名ASCII字母、数字、下划线和冒号,他必须配正则表达式[a-zA-Z_:][a-zA-Z0-9_:]*。

标签开启了Prometheus的多维数据模型:对于相同的度量名称,通过不同标签列表的结合, 会形成特定的度量维度实例。

例如:所有包含度量名称为/api/tracks的http请求,打上method=POST的标签,则形成了具体的http请求。这个查询语言在这些度量和标签列表的基础上进行过滤和聚合。改变任何度量上的任何标签值,则会形成新的时间序列图。

标签label名称可以包含ASCII字母、数字和下划线。它们必须匹配正则表达式[a-zA-Z_][a-zA-Z0-9_]*。带有_下划线的标签名称被保留内部使用。

标签labels值包含任意的Unicode码。

具体详见metrics和labels命名最佳实践。

有序的采样值

有序的采样值形成了实际的时间序列数据列表。每个采样值包括:

  • 一个64位的浮点值。
  • 一个精确到毫秒级的时间戳。
  • 一个样本数据集是针对一个指定的时间序列在一定时间范围的数据收集。这个时间序列是由<metric_name>{<label_name>=<label_value>, …}。

小结:指定度量名称和度量指标下的相关标签值,则确定了所关心的目标数据,随着时间推移形成一个个点,在图表上实时绘制动态变化的线条。

Notation(符号)

表示一个度量指标和一组键值对标签,需要使用以下符号:

[metric name]{[label name]=[label value], …}

例如,度量指标名称是api_http_requests_total,标签为method=“POST”, handler="/messages" 的示例如下所示:

api_http_requests_total{method=“POST”, handler="/messages"}

这些命名和OpenTSDB使用方法是一样的。

度量指标模型

metrics类型

Prometheus客户库提供了四个核心的metrics类型。这四种类型目前仅在客户库和wire协议中区分。Prometheus服务还没有充分利用这些类型。不久的将来就会发生改变。

Counter(计数器)

counter 是一个累计度量指标,它是一个只能递增的数值。计数器主要用于统计服务的请求数、任务完成数和错误出现的次数等等。计数器是一个递增的值。

反例:统计goroutines的数量。计数器的使用方式在下面的各个客户端例子中:

客户端使用计数器的文档:

  • Go
  • Java
  • Python
  • Ruby

Gauge(测量器)

gauge是一个度量指标,它表示一个既可以递增, 又可以递减的值。

测量器主要测量类似于温度、当前内存使用量等,也可以统计当前服务运行随时增加或者减少的Goroutines数量。

客户端使用计量器的文档:

  • Go
  • Java
  • Python
  • Ruby

Histogram(柱状图)

histogram,是柱状图,在Prometheus系统中的查询语言中,有三种作用:

  • 对每个采样点进行统计,打到各个分类值中(bucket)。
  • 对每个采样点值累计和(sum)。
  • 对采样点的次数累计和(count)。

度量指标名称: [basename]的柱状图, 上面三类的作用度量指标名称:

  • [basename]_bucket{le=“上边界”}, 这个值为小于等于上边界的所有采样点数量。
  • [basename]_sum
  • [basename]_count

小结:所以如果定义一个度量类型为Histogram,则Prometheus系统会自动生成三个对应的指标。

使用histogram_quantile()函数,计算直方图或者是直方图聚合计算的分位数阈值。一个直方图计算Apdex值也是合适的, 当在buckets上操作时,记住直方图是累计的。

客户库的直方图使用文档:

  • Go
  • Java
  • Python
  • Ruby

[Summary]总结

类似histogram柱状图,summary是采样点分位图统计。(通常的使用场景:请求持续时间和响应大小)。它也有三种作用:

对于每个采样点进行统计,并形成分位图。(如:正态分布一样,统计低于60分不及格的同学比例,统计低于80分的同学比例,统计低于95分的同学比例)

  • 统计班上所有同学的总成绩(sum)。
  • 统计班上同学的考试总人数(count)。
  • 带有度量指标的[basename]的summary 在抓取时间序列数据展示。

观察时间的φ-quantiles (0 ≤ φ ≤ 1), 显示为[basename]{分位数="[φ]"}。

  • [basename]_sum, 是指所有观察值的总和。
  • [basename]_count, 是指已观察到的事件计数值。

详见histogram和summaries。

有关summaries的客户端使用文档:

  • Go
  • Java
  • Python
  • Ruby

任务与实例

Jobs和Instances(任务和实例)

就Prometheus而言,pull拉取采样点的端点服务称之为instance。多个这样pull拉取采样点的instance, 则构成了一个job。

例如, 一个被称作api-server的任务有四个相同的实例。

job: api-server

  • instance 1:1.2.3.4:5670
  • instance 2:1.2.3.4:5671
  • instance 3:5.6.7.8:5670
  • instance 4:5.6.7.8:5671

自动化生成的标签和时间序列:

当Prometheus拉取一个目标, 会自动地把两个标签添加到度量名称的标签列表中,分别是:

  • job: 目标所属的配置任务名称api-server。
  • instance:采样点所在服务:host:port。

如果以上两个标签二者之一存在于采样点中,这个取决于honor_labels配置选项。

对于每个采样点所在服务instance,Prometheus都会存储以下的度量指标采样点:

  • up{job="[job-name]", instance=“instance-id”}: up值=1,表示采样点所在服务健康; 否则,网络不通, 或者服务挂掉了。
  • scrape_duration_seconds{job="[job-name]", instance="[instance-id]"}: 尝试获取目前采样点的时间开销。
  • scrape_samples_post_metric_relabeling{job="", instance=""}:表示度量指标的标签变化后,标签没有变化的度量指标数量。
  • scrape_samples_scraped{job="", instance=""}: 这个采样点目标暴露的样本点数量。

备注:我查了下scrape_samples_post_metric_relabeling 和 scrape_samples_scraped的值好像是一样的。还是这两个值没有理解。

up度量指标对服务健康的监控是非常有用的。

查询

Prometheus提供一个函数式的表达式语言,可以使用户实时地查找和聚合时间序列数据。

表达式计算结果可以在图表中展示,也可以在Prometheus表达式浏览器中以表格形式展示,或者作为数据源, 以HTTP API的方式提供给外部系统使用。

examples

这个文档仅供参考, 这里先举几个容易上手的例子。

表达式语言数据类型:

在Prometheus的表达式语言中,任何表达式或者子表达式都可以归为四种类型:

  • instant vector 瞬时向量 - 它是指在同一时刻,抓取的所有度量指标数据。这些度量指标数据的key都是相同的,也即相同的时间戳。
  • rangevector 范围向量 - 它是指在任何一个时间范围内,抓取的所有度量指标数据。
  • scalar 标量 - 一个简单的浮点值。
  • string 字符串 - 一个当前没有被使用的简单字符串。

依赖于使用场景(例如:图表 vs. 表格),根据用户所写的表达式,仅仅只有一部分类型才适用这种表达式。例如:瞬时向量类型是唯一可以直接在图表中使用的。

Literals

字符串:

字符串可以用单引号、双引号或者反引号表示。

PromQL遵循与Go相同的转义规则。在单引号,双引号中,反斜杠成为了转义字符,后面可以跟着a, b, f, n, r, t, v或者\。可以使用八进制(\nnn)或者十六进制(\xnn, \unnnn和\Unnnnnnnn)提供特定字符。

在反引号内不处理转义字符。与Go不同,Prom不会丢弃反引号中的换行符。例如:

  • “this is a string”
  • ‘these are unescaped: \n \ \t’
  • these are not unescaped: \n ’ " \t"’

浮点数:

标量浮点值可以直接写成形式-[.(digits)]。

-2.43

  • 时间序列选择器
  • 即时向量选择器
  • 瞬时向量选择器可以对一组时间序列数据进行筛选,并给出结果中的每个结果键值对(时间戳-样本值)。
    最简单的形式是,只有一个度量名称被指定。在一个瞬时向量中这个结果包含有这个度量指标名称的所有样本数据键值对。

下面这个例子选择所有时间序列度量名称为http_requests_total的样本数据:

http_requests_total

通过在度量指标后面增加{}一组标签可以进一步地过滤这些时间序列数据。

下面这个例子选择了度量指标名称为http_requests_total,且一组标签为 job=prometheus, group=canary:

http_requests_total{job=“prometheus”,group=“canary”}

可以采用不匹配的标签值也是可以的,或者用正则表达式不匹配标签。标签匹配操作如下所示:

  • =: 精确地匹配标签给定的值。
  • !=: 不等于给定的标签值。
  • =~: 正则表达匹配给定的标签值。
  • !=: 给定的标签值不符合正则表达式。

例如:度量指标名称为http_requests_total,正则表达式匹配标签environment为staging, testing, development的值,且http请求方法不等于GET。

http_requests_total{environment=~“staging|testing|development”, method!=“GET”}

匹配空标签值的标签匹配器也可以选择没有设置任何标签的所有时间序列数据。正则表达式完全匹配。

向量选择器必须指定一个度量指标名称或者至少不能为空字符串的标签值。以下表达式是非法的:

{job=~".*"} #Bad

上面这个例子既没有度量指标名称,标签选择器也可以正则匹配空标签值,所以不符合向量选择器的条件。

相反地,下面这些表达式是有效的,第一个一定有一个字符。第二个有一个有用的标签method:

{job=~".+"} # Good!
{job=~".*", method=“get”} # Good!

标签匹配器能够被应用到度量指标名称,使用__name__标签筛选度量指标名称。

例如:表达式http_requests_total等价于{name=“http_requests_total”}。其他的匹配器,如:= ( !=, =~, !~)都可以使用。下面的表达式选择了度量指标名称以job:开头的时间序列数据:

{name=~"^job:.*"} #

范围向量选择器:

范围向量类似瞬时向量, 不同在于,它们从当前实例选择样本范围区间。在语法上,时间长度被追加在向量选择器尾部的方括号[]中,用以指定对于每个样本范围区间中的每个元素应该抓取的时间范围样本区间。

时间长度有一个数值决定,后面可以跟下面的单位:

  • s - seconds
  • m - minutes
  • h - hours
  • d - days
  • w - weeks
  • y - years

在下面这个例子中, 选择过去5分钟内,度量指标名称为http_requests_total, 标签为job="prometheus"的时间序列数据:


http_requests_total{job=“prometheus”}[5m]


偏移修饰符:

这个offset偏移修饰符允许在查询中改变单个瞬时向量和范围向量中的时间偏移。

例如,下面的表达式返回相对于当前时间的前5分钟时的时刻, 度量指标名称为http_requests_total的时间序列数据:


http_requests_total offset 5m


注意:offset偏移修饰符必须直接跟在选择器后面,例如:


sum(http_requests_total{method=“GET”} offset 5m) // GOOD.


然而,下面这种情况是不正确的:


sum(http_requests_total{method=“GET”}) offset 5m // INVALID.


offset偏移修饰符在范围向量上和瞬时向量用法一样的。下面这个返回了相对于当前时间的前一周时,过去5分钟的度量指标名称为http_requests_total的速率:


rate(http_requests_total[5m] offset 1w)


操作符:

Prometheus支持二元和聚合操作符。

函数:

Prometheus提供了一些函数列表操作时间序列数据。

陷阱:

插值和陈旧

当运行查询后,独立于当前时刻被选中的时间序列数据所对应的时间戳,这个时间戳主要用来进行聚合操作,包括sum, avg等,大多数聚合的时间序列数据所对应的时间戳没有对齐。

由于它们的独立性,我们需要在这些时间戳中选择一个时间戳,并已这个时间戳为基准,获取小于且最接近这个时间戳的时间序列数据。

如果5分钟内,没有获取到任何的时间序列数据,则这个时间戳不会存在。那么在图表中看到的数据都是在当前时刻5分钟前的数据。

注意:差值和陈旧处理可能会发生变化。详见https://github.com/prometheus/prometheus/issues/398https://github.com/prometheus/prometheus/issues/581

避免慢查询和高负载

如果一个查询需要操作非常大的数据量,图表绘制很可能会超时,或者服务器负载过高。

因此,在对未知数据构建查询时,始终需要在Prometheus表达式浏览器的表格视图中构建查询,直到结果是看起来合理的(最多为数百个,而不是数千个)。

只有当你已经充分过滤或者聚合数据时,才切换到图表模式。如果表达式的查询结果仍然需要很长时间才能绘制出来,则需要通过记录规则重新清洗数据。

像api_http_requests_total这样简单的度量指标名称选择器,可以扩展到具有不同标签的数千个时间序列中,这对于Prometheus的查询语言是非常重要的。

还要记住,聚合操作即使输出的结果集非常少,但是它会在服务器上产生负载。这类似于关系型数据库查询可一个字段的总和,总是非常缓慢。

操作符

二元操作符:

Prometheus的查询语言支持基本的逻辑运算和算术运算。对于两个瞬时向量, 匹配行为可以被改变。

算术二元运算符:

在Prometheus系统中支持下面的二元算术操作符:

  • +加法
  • -减法
  • *乘法
  • /除法
  • % 模
  • ^ 幂等

二元运算操作符支持scalar/scalar(标量/标量)、vector/scalar(向量/标量)、和vector/vector(向量/向量)之间的操作。

在两个标量之间进行操作符运算,得到的结果也是标量。

在向量和标量之间,这个操作符会作用于这个向量的每个样本值上。例如:如果一个时间序列瞬时向量除以2,操作结果也是一个新的瞬时向量,且度量指标名称不变, 它是原度量指标瞬时向量的每个样本值除以2。

在两个向量之间,一个二元算术操作符作用在左边瞬时向量的每个样本值,且该样本值与操作符右边能匹配上的样本值计算,向量匹配。结果写入到一个没有度量指标名称的瞬时向量。

比较二元操作符:

在Prometheus系统中,比较二元操作符有:

  • == 等于
  • != 不等于
  • > 大于
  • < 小于
  • >= 大于等于
  • <= 小于等于

比较二元操作符被应用于scalar/scalar(标量/标量)、vector/scalar(向量/标量),和vector/vector(向量/向量)。比较操作符得到的结果是bool布尔类型值,返回1或者0值。

在两个标量之间的比较运算,bool结果写入到另一个结果标量中。

瞬时向量和标量之间的比较运算,这个操作符会应用到某个当前时刻的每个时间序列数据上,如果一个时间序列数据值与这个标量比较结果是false,则这个时间序列数据被丢弃掉,如果是true, 则这个时间序列数据被保留在结果中。

在两个瞬时向量之间的比较运算,左边度量指标数据中的每个时间序列数据,与右边度量指标中的每个时间序列数据匹配。

没有匹配上的,或者计算结果为false的,都被丢弃,不在结果中显示。否则将保留左边的度量指标和标签的样本数据写入瞬时向量。

逻辑/集合二元操作符

逻辑/集合二元操作符只能作用在即时向量, 包括:

  • and 交集
  • or 并集
  • unless 补集

vector1 and vector2 的逻辑/集合二元操作符,规则:vector1瞬时向量中的每个样本数据与vector2向量中的所有样本数据进行标签匹配,不匹配的,全部丢弃。运算结果是保留左边的度量指标名称和值。

vector1 or vector2的逻辑/集合二元操作符,规则: 保留vector1向量中的每一个元素,对于vector2向量元素,则不匹配vector1向量的任何元素,则追加到结果元素中。

vector1 unless vector2的逻辑/集合二元操作符,又称差积。规则:包含在vector1中的元素,但是该元素不在vector2向量所有元素列表中,则写入到结果集中。

向量匹配

向量之间的匹配是指右边向量中的每一个元素,在左边向量中也存在。这里有两种基本匹配行为特征:

一对一,找到这个操作符的两边向量元素的相同元素。默认情况下,操作符的格式是vector1 [operate] vector2。

如果它们有相同的标签和值,则表示相匹配。ingoring关键字是指,向量匹配时,可以忽略指定标签。on关键字是指,在指定标签上进行匹配。格式如下所示:

[vector expr] [bin-op] ignoring([label list]) [vector expr]
[vector expr] [bin-op] on([lable list]) [vector expr]

例如样本数据:

method_code:http_errors:rate5m{method=“get”, code=“500”} 24
method_code:http_errors:rate5m{method=“get”, code=“404”} 30
method_code:http_errors:rate5m{method=“put”, code=“501”} 3
method_code:http_errors:rate5m{method=“post”, code=“404”} 21
method:http_requests:rate5m{method=“get”} 600
method:http_requests:rate5m{method=“delete”} 34
method:http_requests:rate5m{method=“post”} 120

查询例子:

method_code:http_errors:rate5m{code=“500”} / ignoring(code) method:http_requests:rate5m

两个向量之间的除法操作运算的向量结果是,每一个向量样本http请求方法标签值是500,且在过去5分钟的运算值。

如果没有忽略code="500"的标签,这里不能匹配到向量样本数据。两个向量的请求方法是put和delete的样本数据不会出现在结果列表中。

{method=“get”} 0.04 // 24 / 600
{method=“post”} 0.05 // 6 / 120

多对一和一对多的匹配,是指向量元素中的一个样本数据匹配标签到了多个样本数据标签。这里必须直接指定两个修饰符group_left或者group_right, 左或者右决定了哪边的向量具有较高的子集:

ignoring() group_left()
ignoring() group_right()
on() group_left()
on() group_right()

这个group带标签的修饰符标签列表包含了“一对多”中的“一”一侧的额外标签。对于on标签只能是这些列表中的一个。结果向量中的每一个时间序列数据都是唯一的。

group修饰符只能被用在比较操作符和算术运算符。

查询例子:

method_code:http_errors:rate5m / ignoring(code) group_left method:http_requests:rate5m

在这个例子中,左向量的标签数量多于左边向量的标签数量,所以我们使用group_left。右边向量的时间序列元素匹配左边的所有相同method标签:

{method=“get”, code=“500”} 0.04 // 24 /600
{method=“get”, code=“404”} 0.05 // 30 /600
{method=“post”, code=“500”} 0.05 // 6 /600
{method=“post”, code=“404”} 0.175 // 21 /600

多对一和一对多匹配应该更多地被谨慎使用。经常使用ignoring(<labels>)输出想要的结果。

聚合操作符

Prometheus支持下面的内置聚合操作符。这些聚合操作符被用于聚合单个即时向量的所有时间序列列表,把聚合的结果值存入到新的向量中。

  • sum (在维度上求和)
  • max(在维度上求最大值)
  • min (在维度上求最小值)
  • avg(在维度上求平均值)
  • stddev(求标准差)
  • stdvar(求方差)
  • count (统计向量元素的个数)
  • count_values (统计相同数据值的元素数量)
  • bottomk(样本值第k个最小值)
  • topk (样本值第k个最大值)
  • quantile(统计分位数)

这些操作符被用于聚合所有标签维度,或者通过without或者by子句来保留不同的维度:

([parameter,] ) [without | by ()] [keep_common]

parameter只能用于count_values, quantile, topk和bottomk。without移除结果向量中的标签集合,其他标签被保留输出。

by关键字的作用正好相反,即使它们的标签值在向量的所有元素之间。keep_common子句允许保留额外的标签(在元素之间相同,但不在by子句中的标签)。

count_values对每个唯一的样本值输出一个时间序列。每个时间序列都附加一个标签。这个标签的名字有聚合参数指定,同时这个标签值是唯一的样本值。每一个时间序列值是结果样本值出现的次数。

topk和bottomk与其他输入样本子集聚合不同,返回的结果中包括原始标签。by和without仅仅用在输入向量的桶中。

例如:

如果度量指标名称http_requests_total包含由group, application, instance的标签组成的时间序列数据,我们可以通过以下方式计算去除instance标签的http请求总数:

sum(http_requests_total) without (instance)

如果我们对所有应用程序的http请求总数,我们可以简单地写下:

sum(http_requests_total)

统计每个编译版本的二进制文件数量,我们可以如下写:

count_values(“version”, build_version)

通过所有实例,获取http请求第5个最大值,我们可以简单地写下:

topk(5, http_requests_total)

二元运算符优先级

在Prometheus系统中,二元运算符优先级从高到低:

  • ^
  • *, /, %
  • +, -
  • ==, !=, <=, <, >=, >
  • and, unless
  • or

prometheus histogram 类型 prometheus group left_linux