Prometheus的rate函数是怎么计算的(不太靠谱)

发布时间 2023-07-28 15:26:41作者: 南风丶轻语

Prometheus的rate函数是怎么计算的(不太靠谱)

前言

测试的数据类型是Counter类型,其他类型没测试,好像是类型改变了,rate函数的算法也变了

抓取的原始数据

抓取间隔是15s

开始抓取到数据的时间是2023-07-27 14:14:34

第二个时间是2023-07-27 14:14:49(第一个时间+15s)

第三个时间是2023-07-27 14:15:04(第二个时间+15s)

。。。。。。依次类推,非常合理,每15秒抓一次

最后的时间是2023-07-27 14:18:19(上一个时间+15s)

数据如下表

时间
2023-07-27 14:14:34 30
2023-07-27 14:14:49 150
2023-07-27 14:15:04 360
2023-07-27 14:15:19 660
2023-07-27 14:15:34 1050
2023-07-27 14:15:49 1530
2023-07-27 14:16:04 2100
2023-07-27 14:16:19 2760
2023-07-27 14:16:34 3510
2023-07-27 14:16:49 4350
2023-07-27 14:17:04 5280
2023-07-27 14:17:19 6300
2023-07-27 14:17:34 7410
2023-07-27 14:17:49 8610
2023-07-27 14:18:04 9900
2023-07-27 14:18:19 11280

分析query如果获取数据

先看一下,使用不同的开始时间和结束时间,不同的步长来查询Prometheus的数据,结果会是怎么样的,就能知道query是怎么根据查询的起始时间,结束时间和步长来获取值的

回忆一下

数据的开始时间是2023-07-27 14:14:34

数据的结束时间是2023-07-27 14:18:19

开始查询

查询1

设置查询的开始时间是2023-07-27 14:14:30

设置查询的结束时间是2023-07-27 14:18:30

设置步长为1

查询到的数据如下图

可以看出,没获取到新的数据前,数据是保持不变的,而不是空白或者0,只有下一次数据被获取到后,才会更新数据,然后数据就是保持下去,直到无法获取到数据(例如,exporter崩溃了)

image-20230727150907414

查询2

设置查询的开始时间是2023-07-27 14:14:30

设置查询的结束时间是2023-07-27 14:18:30

设置步长为3

查询到的数据如下图

获取数据的规则是这样的

  1. 以开始时间为起始时间
  2. 加上步长为第一个时间
  3. 再加步长为第二个时间
  4. 再加步长为第三个时间
  5. 以此类推
  6. 然后拿该时间向前看,找到最接近这个时间的获取到数据的那个时间
  7. 然后拿那个时间对应的值作为数据返回
  8. 如果那时候还没有值,则抛弃该时间

例如

查询的开始时间是2023-07-27 14:14:30

设置步长为3

则起始时间是2023-07-27 14:14:30(第一个有数据的时间是2023-07-27 14:14:34,因此抛弃改时间)

第一个时间是2023-07-27 14:14:33(第一个有数据的时间是2023-07-27 14:14:34,因此抛弃改时间)

第二个时间是2023-07-27 14:14:36(第二个数据的时间是2023-07-27 14:14:49,第一个数据的时间是2023-07-27 14:14:34,因此取第一个有数据的时间2023-07-27 14:14:34对应的值)

第三个时间是2023-07-27 14:14:39(第二个数据的时间是2023-07-27 14:14:49,第一个数据的时间是2023-07-27 14:14:34,因此取第一个有数据的时间2023-07-27 14:14:34对应的值)

第四个时间是2023-07-27 14:14:42(第二个数据的时间是2023-07-27 14:14:49,第一个数据的时间是2023-07-27 14:14:34,因此取第一个有数据的时间2023-07-27 14:14:34对应的值)

...

第N个时间是2023-07-27 14:14:51(第四个数据的时间是2023-07-27 14:15:19,第三个数据的时间是2023-07-27 14:14:49,因此取第三个数据的时间2023-07-27 14:14:49对应的值)

image-20230727153110649

备注

想要查看获取的数据,可以使用该脚本,替换自己的查询条件即可

import datetime
import time

from prometheus_api_client import PrometheusConnect


def timestamp_to_str(timestamp: int):
    # 转换成localtime
    time_local = time.localtime(timestamp)
    # 转换成新的时间格式(2016-05-05 20:28:54)
    dt = time.strftime("%Y-%m-%d %H:%M:%S", time_local)
    return dt


prom = PrometheusConnect(url="http://172.17.135.202:9090", headers=None, disable_ssl=True)
ok = prom.check_prometheus_connection()  # 检查连接状态
print(f"连接Prometheus:{prom.url}, 状态:{'连接成功' if ok else '连接失败'}")

query = "my_counter_total"
start_time = datetime.datetime.strptime("2023-07-27 14:14:30", '%Y-%m-%d %H:%M:%S')

end_time = datetime.datetime.strptime("2023-07-27 14:18:30", '%Y-%m-%d %H:%M:%S')

step = "60s"

data = prom.custom_query_range(query, start_time, end_time, step)
values = data[0]['values']
for value in values:
    t = timestamp_to_str(value[0])
    v = value[1]
    print(f"{t}            {v}")
print(len(values))

Rate函数是怎么计算的

分析完query是怎么从Prometheus获取的数据,接下来看看Rate函数是怎么计算的

简单来说就是(终止值-起始值)/时间间隔

例如,

  • 2023-07-27 14:18:30为终止时间
  • 要计算1m中内的变化率

执行查询

image-20230728145739090

也可以使用python代码获取数据

image-20230728145807116

执行rate函数

image-20230728145944354

也可以使用python代码获取数据

image-20230728150030157

验证rate函数计算方式

使用最后一个获取到的值11280减去第一个获取到的值7410

然后除以(最后一个获取到值的时间1690438698.358减去第一个获取到值的时间1690438653.358 )

(11280-7410)/(1690438698.358-1690438653.358)=86.0

验证成功

python代码

import datetime
import time

from prettytable import PrettyTable
from prometheus_api_client import PrometheusConnect

t_format = '%Y-%m-%d %H:%M:%S'


def timestamp_to_str(timestamp: int):
    time_local = time.localtime(timestamp)
    dt = time.strftime(t_format, time_local)
    return dt


def datetime_to_timestamp(t: datetime.datetime):
    return t.timestamp()


prom = PrometheusConnect(url="http://172.17.135.202:9090", headers=None, disable_ssl=True)
ok = prom.check_prometheus_connection()  # 检查连接状态
print(f"连接Prometheus:{prom.url}, 状态:{'连接成功' if ok else '连接失败'}")

interval = 1
query = f"my_counter_total[{interval}m]"
t = datetime.datetime.strptime("2023-07-27 14:18:30", t_format)
t_timestamp = datetime_to_timestamp(t)

data = prom.custom_query(query, {"time": t_timestamp})
table = PrettyTable()
values = data[0]['values']
table.field_names = ("Time", 'Value')
for value in values:
    t = timestamp_to_str(value[0])
    v = value[1]
    table.add_row((t, v))
print(table)
print()
print("执行rate函数")
query = f"rate(my_counter_total{{}}[{interval}m])"
data = prom.custom_query(query, {"time": t_timestamp})
t = timestamp_to_str(data[0]['value'][0])
v = data[0]['value'][1]
table = PrettyTable()
table.field_names = ("Time", 'Value')
# print(f"{t}            {v}")
table.add_row((t, v))
print(table)

print()
print("验证rate函数")
table = PrettyTable()
table.field_names = ("Last Value", 'First Value')
table.add_row([values[-1][1],values[0][1]])
print(table)

table = PrettyTable()
table.field_names = ("Last Time", 'First Time')
table.add_row([f"{values[-1][0]}\n{timestamp_to_str(values[-1][0])}",f"{values[0][0]}\n{timestamp_to_str(values[0][0])}"])
print(table)
print((float(values[-1][1])-float(values[0][1]))/(float(values[-1][0])-float(values[0][0])))

因此,可以简单理解为rate函数的计算方式为(终止值-起始值)/时间间隔

但是,我测试了,把间隔1m,改为2m,3m,4m,5m,6m,7m...(可使用python脚本调试)

当大于等于5m时,该公式就失败了,验证不通过了,最终要看源码了,网上也rate源码的解析,可以参考一下

(45条消息) 普罗米修斯irate/rate算法区别(原创)_普罗米修斯 rate_工程师阿杜的博客-CSDN博客

容器 - Prometheus rate 函数算法 - 个人文章 - SegmentFault 思否