Prometheus的rate函数是怎么计算的(不太靠谱)
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崩溃了)
查询2
设置查询的开始时间是2023-07-27 14:14:30
设置查询的结束时间是2023-07-27 14:18:30
设置步长为3
秒
查询到的数据如下图
获取数据的规则是这样的
- 以开始时间为起始时间
- 加上步长为第一个时间
- 再加步长为第二个时间
- 再加步长为第三个时间
- 以此类推
- 然后拿该时间向前看,找到最接近这个时间的获取到数据的那个时间
- 然后拿那个时间对应的值作为数据返回
- 如果那时候还没有值,则抛弃该时间
例如
查询的开始时间是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
对应的值)
备注
想要查看获取的数据,可以使用该脚本,替换自己的查询条件即可
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中内的变化率
执行查询
也可以使用python代码获取数据
执行rate函数
也可以使用python代码获取数据
验证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源码的解析,可以参考一下