PromQL 内置函数_直方图

1. rate()

​rate(v range-vector)​​ 函数可以直接计算区间向量 v 在时间窗口内平均增长速率,它会在单调性发生变化时(如由于采样目标重启引起的计数器复位)自动中断。该函数的返回结果不带有度量指标,只有标签列表。

例如,以下表达式返回区间向量中每个时间序列过去 5 分钟内 HTTP 请求数的每秒增长率: 

rate(http_requests_total[5m])

结果:
{code="200",handler="label_values",instance="120.77.65.193:9090",job="prometheus",method="get"} 0
{code="200",handler="query_range",instance="120.77.65.193:9090",job="prometheus",method="get"} 0
{code="200",handler="prometheus",instance="120.77.65.193:9090",job="prometheus",method="get"} 0.2
...

rate() 函数返回值类型只能用计数器,在长期趋势分析或者告警中推荐使用这个函数。 

当将 ​​rate()​​​ 函数与​​聚合运算符​​​(例如 ​​sum()​​​)或随时间聚合的函数(任何以 ​​_over_time​​ 结尾的函数)一起使用时,必须先执行 rate 函数,然后再进行聚合操作,否则当采样目标重新启动时 rate() 无法检测到计数器是否被重置。 

2. irate()


​irate(v range-vector)​​ 函数用于计算区间向量的增长率,但是其反应出的是瞬时增长率。irate 函数是通过区间向量中最后两个两本数据来计算区间向量的增长速率,它会在单调性发生变化时(如由于采样目标重启引起的计数器复位)自动中断。这种方式可以避免在时间窗口范围内的“长尾问题”,并且体现出更好的灵敏度,通过irate函数绘制的图标能够更好的反应样本数据的瞬时变化状态。

例如,以下表达式返回区间向量中每个时间序列过去 5 分钟内最后两个样本数据的 HTTP 请求数的增长率:

irate(http_requests_total{job="api-server"}[5m])

irate 只能用于绘制快速变化的计数器,在长期趋势分析或者告警中更推荐使用 rate 函数。因为使用 irate 函数时,速率的简短变化会重置 ​​FOR​​ 语句,形成的图形有很多波峰,难以阅读。

 注意

当将 ​​irate()​​​ 函数与​​聚合运算符​​​(例如 ​​sum()​​​)或随时间聚合的函数(任何以 ​​_over_time​​ 结尾的函数)一起使用时,必须先执行 irate 函数,然后再进行聚合操作,否则当采样目标重新启动时 irate() 无法检测到计数器是否被重置。

3. increase()


​increase(v range-vector)​​ 函数获取区间向量中的第一个和最后一个样本并返回其增长量, 它会在单调性发生变化时(如由于采样目标重启引起的计数器复位)自动中断。由于这个值被外推到指定的整个时间范围,所以即使样本值都是整数,你仍然可能会得到一个非整数值。

例如,以下表达式返回区间向量中每个时间序列过去 5 分钟内 HTTP 请求数的增长数:

4. deriv()


​deriv(v range-vector)​​​ 的参数是一个区间向量,返回一个瞬时向量。它使用​​简单的线性回归​​计算区间向量 v 中各个时间序列的导数。

这个函数一般只用在 Gauge 类型的时间序列上。

rate()​irate()​ 和 ​increase()​ 函数只能输出非负值的结果,对于跟踪一个可以上升或下降的值的指标(如温度、内存或磁盘空间),可以使用 ​​delta()​​​ 和 ​​deriv()​​ 函数来代替。 

​deriv()​​​ 函数可以计算一个区间向量中各个时间序列二阶导数,使用简单线性回归,​​deriv(v range-vector)​​ 的参数是一个区间向量,返回一个瞬时向量,这个函数一般只用在 Gauge 类型的时间序列上。例如,要计算在 15 分钟的窗口下,每秒钟磁盘使用量上升或下降了多少:

PromQL 内置函数_时间序列_02

5. predict_linear()  预测Gauge指标变化趋势


  • 饱和度:衡量当前服务的饱和度。

主要强调最能影响服务状态的受限制的资源。 例如,如果系统主要受内存影响,那就主要关注系统的内存状态,如果系统主要受限与磁盘I/O,那就主要观测磁盘I/O的状态。因为通常情况下,当这些资源达到饱和后,服务的性能会明显下降。同时还可以利用饱和度对系统做出预测,比如,“磁盘是否可能在4个小时候就满了”。

​predict_linear(v range-vector, t scalar)​​ 函数可以预测时间序列 v 在 t 秒后的值。它基于简单线性回归的方式,对时间窗口内的样本数据进行统计,从而可以对时间序列的变化趋势做出预测。该函数的返回结果不带有度量指标,只有标签列表。

例如,基于 2 小时的样本数据,来预测主机可用磁盘空间的是否在 4 个小时候被占满,可以使用如下表达式:

predict_linear(node_filesystem_free{job="node"}[2h], 4 * 3600) < 0

通过下面的例子来观察返回值:

predict_linear(http_requests_total{code="200",instance="120.77.65.193:9090",job="prometheus",method="get"}[5m], 5)
结果:
{code="200",handler="query_range",instance="120.77.65.193:9090",job="prometheus",method="get"} 1
{code="200",handler="prometheus",instance="120.77.65.193:9090",job="prometheus",method="get"} 4283.449995397104
{code="200",handler="static",instance="120.77.65.193:9090",job="prometheus",method="get"} 22.99999999999999
...

这个函数一般只用在 Gauge 类型的时间序列上。

在一般情况下,系统管理员为了确保业务的持续可用运行,会针对服务器的资源设置相应的告警阈值。例如,当磁盘空间只剩512MB时向相关人员发送告警通知。 这种基于阈值的告警模式对于当资源用量是平滑增长的情况下是能够有效的工作的。 但是如果资源不是平滑变化的呢? 比如有些某些业务增长,存储空间的增长速率提升了高几倍。这时,如果基于原有阈值去触发告警,当系统管理员接收到告警以后可能还没来得及去处理问题,系统就已经不可用了。 因此阈值通常来说不是固定的,需要定期进行调整才能保证该告警阈值能够发挥去作用。 那么还有没有更好的方法吗?

PromQL中内置的predict_linear(v range-vector, t scalar) 函数可以帮助系统管理员更好的处理此类情况,predict_linear函数可以预测时间序列v在t秒后的值。它基于简单线性回归的方式,对时间窗口内的样本数据进行统计,从而可以对时间序列的变化趋势做出预测。例如,基于2小时的样本数据,来预测主机可用磁盘空间的是否在4个小时候被占满,可以使用如下表达式:

predict_linear(node_filesystem_free{job="node"}[2h], 4 * 3600) < 0

6. histogram_quantile() 


​histogram_quantile(φ float, b instant-vector)​​ 从 bucket 类型的向量 ​b​​ 中计算 φ (0 ≤ φ ≤ 1) 分位数(百分位数的一般形式)的样本的最大值。(有关 φ 分位数的详细说明以及直方图指标类型的使用,请参阅​​直方图和摘要​​​)。向量 ​b​​ 中的样本是每个 bucket 的采样点数量。每个样本的 labels 中必须要有 ​le​​ 这个 label 来表示每个 bucket 的上边界,没有 ​​le​​ 标签的样本会被忽略。

直方图指标类型自动提供带有 ​_bucket​ 后缀和相应标签的时间序列。

可以使用 ​​rate()​​ 函数来指定分位数计算的时间窗口。

例如,一个直方图指标名称为 ​​employee_age_bucket_bucket​​,要计算过去 10 分钟内 第 90 个百分位数,请使用以下表达式:

histogram_quantile(0.9, rate(employee_age_bucket_bucket[10m]))

返回:

{instance="10.0.86.71:8080",job="prometheus"} 35.714285714285715

这表示最近 10 分钟之内 90% 的样本的最大值为 35.714285714285715。

这个计算结果是每组标签组合成一个时间序列。我们可能不会对所有这些维度(如 ​​job​​​、​​instance​​​ 和 ​​method​​​)感兴趣,并希望将其中的一些维度进行聚合,则可以使用 sum() 函数。例如,以下表达式根据 ​​job​​ 标签来对第 90 个百分位数进行聚合:

# histogram_quantile() 函数必须包含 le 标签
histogram_quantile(0.9, sum(rate(employee_age_bucket_bucket[10m])) by (job, le))

如果要聚合所有的标签,则使用如下表达式:

histogram_quantile(0.9,sum(rate(employee_age_bucket_bucket[10m])) by (le))

 注意

​histogram_quantile​​ 这个函数是根据假定每个区间内的样本分布是线性分布来计算结果值的(也就是说它的结果未必准确),最高的 bucket 必须是 le="+Inf" (否则就返回 NaN)。

如果分位数位于最高的 bucket(+Inf) 中,则返回第二个最高的 bucket 的上边界。如果该 bucket 的上边界大于 0,则假设最低的 bucket 的的下边界为 0,这种情况下在该 bucket 内使用常规的线性插值。

如果分位数位于最低的 bucket 中,则返回最低 bucket 的上边界。

如果 b 含有少于 2 个 buckets,那么会返回 ​​NaN​​​,如果 φ < 0 会返回 ​​-Inf​​​,如果 φ > 1 会返回 ​​+Inf​​​。
 

7. increase()


​increase(v range-vector)​​ 函数获取区间向量中的第一个和最后一个样本并返回其增长量, 它会在单调性发生变化时(如由于采样目标重启引起的计数器复位)自动中断。由于这个值被外推到指定的整个时间范围,所以即使样本值都是整数,你仍然可能会得到一个非整数值。

例如,以下表达式返回区间向量中每个时间序列过去 5 分钟内 HTTP 请求数的增长数:

increase(http_requests_total{job="apiserver"}[5m])

​increase​​​ 的返回值类型只能是计数器类型,主要作用是增加图表和数据的可读性。使用 ​​rate​​ 函数记录规则的使用率,以便持续跟踪数据样本值的变化。

8. time()


​time()​​ 函数返回从 1970-01-01 到现在的秒数。注意:它不是直接返回当前时间,而是时间戳

PromQL 内置函数_直方图_03

PromQL 内置函数_时间序列_04

PromQL 内置函数_直方图_05

然后再添加一个查询来获取节点运行时间的相关信息,可以使用 ​​node_boot_time_seconds​​ 指标来进行计算,查询语句为:

 sum(time() - node_boot_time_seconds{job="node-exporter"})by(instance)

9. sort()


​sort(v instant-vector)​​ 函数对向量按元素的值进行升序排序,返回结果:key: value = 度量指标:样本值[升序排列]。

10. sort_desc()


​sort(v instant-vector)​​ 函数对向量按元素的值进行降序排序,返回结果:key: value = 度量指标:样本值[降序排列]。

11.  ​​topk()​​​ 和 ​​bottomk()​


有的时候我们并不是对所有的时间序列感兴趣,只对最大或最小的几个序列感兴趣,我们可以使用 ​​topk()​​​ 和 ​​bottomk()​​​ 这两个运算符来操作,可以返回 ​​K​​ 个最大或最小的序列,比如只显示每个 path 和 method 的前三的请求率,我们可以使用下面的语句来查询。

topk(3, sum by(path, method) (rate(demo_api_request_duration_seconds_count{job="demo"}[5m])))

PromQL 内置函数_Prometheus_06