前情提要

书接上回,为了获取客户的Prometheus的监控数据,我写了个脚本用来通过API获取监控数据,然后转换成Open metric格式以方便,传输和导入,代码如下。

import datetime
import subprocess
import requests
import sys

"""
http://localhost:9090
"""

prometheus_url = input("请输入Prometheus链接: ")
username = input("请输入用户名: 如无认证,请回车跳过")
password = input("请输入密码:  如无认证,请回车跳过")
print("下面的两个变量只需填写一个或者不填使用默认值")
step = input("请输入每两个数据点间隔(单位秒,建议为5的倍数): ")
hours = input("请输入往前查询的小时数(单位小时,建议不填): ")

auth = None
metric_param = "e"  # 将查询出所有带有elasticsearch的指标

if username != "" and password != "":
    auth = (username, password)


# 检查用户输入是否为数字
def is_number(value):
    try:
        int(value)
        return True
    except ValueError:
        return False


# 如果用户同时设置了hours和step,按用户的输入值查询
if hours != "" and step != "":
    hours = int(hours)
    step = int(step)
    print("将查询过去{}小时的数据,步长为{}秒".format(hours, step))
else:
    # 如果用户没有输入hours和step,使用默认值
    if hours == "" and step == "":
        print("将使用默认值查询")
        hours = 30
        step = 10
    elif hours != "":
        hours = int(hours)
        # 根据用户输入的hours计算step
        step = int(60 * 60 / (11000 / hours)) + 1
        print("将查询过去{}小时的数据,步长为{}秒".format(hours, step))
    elif step != "":
        step = int(step)
        # 根据用户输入的step计算hours
        hours = int(11000 / (60 / step) / 60)
        print("将查询过去{}小时的数据,步长为{}秒".format(hours, step))
    else:
        print("输入的小时数和步长必须为有效的数字。")
        sys.exit(1)
end_time = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ")
query_time = datetime.datetime.now() - datetime.timedelta(hours=hours)
start_time = query_time.strftime("%Y-%m-%dT%H:%M:%SZ")

series = requests.get('{}/api/v1/label/__name__/values'.format(prometheus_url), auth=auth)
if series.status_code != 200:
    print("查询失败,请检查{}/api/v1/label/__name__/values的连通性".format(prometheus_url))
    sys.exit(1)
else:
    metric_list = [queryQL for queryQL in series.json()['data'] if
                   '{}'.format(metric_param) in queryQL]  # 将查询出所有带有elasticsearch的指标
    print("本次一共查询了{}个指标".format(len(metric_list)))
with open('openmetrics.txt', 'w') as f:
    line_count = 0  # 用于统计行数的计数器
    for metric_name in metric_list:
        metric_response = requests.get(
            '{}/api/v1/query_range?query={}&start={}&end={}&step={}s'.format(
                prometheus_url, metric_name, start_time, end_time, step))
        print(metric_response.url)
        if metric_response.status_code != 200:
            print("查询失败,状态码为{}".format(metric_response.status_code))
            sys.exit(1)
        else:
            prometheus_data = metric_response.json()
            for result in prometheus_data['data']['result']:
                metric_name = result['metric']['__name__']
                labels = []
                for key, value in result['metric'].items():
                    if key != '__name__':
                        labels.append(f'{key}="{value}"')
                labels = ','.join(labels)
                openmetrics = []

                for value in result['values']:
                    openmetrics.append(f'{metric_name}{{{labels}}} {value[1]} {value[0]}\n')
                openmetrics = ''.join(openmetrics)
                f.write(openmetrics)
                line_count += openmetrics.count('\n')  # 统计写入的行数

    f.write('# EOF\n')  # 文档末尾标志必须添加,promtool才能正常识别
    with open('./note.txt', 'a') as f:  # 使用'a'模式来追加内容
        f.write('\n')
        f.write("本次查询的时间范国数据为{},查询的步长为{}秒,共查询了{}种指标,共写入{}行数据".format(
             end_time, step, len(metric_list), line_count))

    # print("写入完成,共写入{}行数据".format(line_count))
    # subprocess.run(['gzip', 'openmetrics.txt'])  # 脚本运行完毕后自动压缩文本文件

已知我本地测试的Prometheus 采集频率是每秒一次,假设我们把一秒当作最小的单位,那么可以说采集到的监控数据是连续的一条线,根据代码中的公式hours = int(11000 / (60 / step) / 60),我们说当步长越大时,跨步就越大,那么数据点的数量应该越小,就好比你走同一段路,你迈的步子越大,是不是需要的步数就越少。

为了记录每一次的步长所以在代码的最后面将每次查询的参数记录到另一个文本中,如下所示

#没有停止各种exporter,数据会不停的增加
本次查询的时间范围数据为2023-09-25T19:28:22Z,查询的步长为5秒,共查询了593种指标,共写入9265448行数据
本次查询的时间范围数据为2023-09-25T19:29:41Z,查询的步长为10秒,共查询了593种指标,共写入7027362行数据
本次查询的时间范围数据为2023-09-25T19:31:04Z,查询的步长为6秒,共查询了593种指标,共写入10554827行数据
本次查询的时间范围数据为2023-09-25T19:31:40Z,查询的步长为12秒,共查询了593种指标,共写入5942033行数据
本次查询的时间范围数据为2023-09-25T19:32:14Z,查询的步长为60秒,共查询了593种指标,共写入6093494行数据
本次查询的时间范围数据为2023-09-25T19:33:08Z,查询的步长为30秒,共查询了593种指标,共写入4305816行数据
本次查询的时间范围数据为2023-09-25T19:33:39Z,查询的步长为15秒,共查询了593种指标,共写入4897653行数据
本次查询的时间范围数据为2023-09-25T19:34:03Z,查询的步长为45秒,共查询了593种指标,共写入5551486行数据
本次查询的时间范围数据为2023-09-25T19:37:27Z,查询的步长为55秒,共查询了593种指标,共写入5826733行数据
本次查询的时间范围数据为2023-09-25T19:38:07Z,查询的步长为6秒,共查询了593种指标,共写入10711991行数据

#停止了exporter但是并不是完全没有变动
本次查询的时间范围数据为2023-09-25T19:46:03Z,查询的步长为5秒,共查询了593种指标,共写入9281524行数据
本次查询的时间范围数据为2023-09-25T19:46:32Z,查询的步长为6秒,共查询了593种指标,共写入10808191行数据
本次查询的时间范围数据为2023-09-25T19:46:57Z,查询的步长为7秒,共查询了593种指标,共写入9272944行数据
本次查询的时间范围数据为2023-09-25T19:47:22Z,查询的步长为8秒,共查询了593种指标,共写入8113585行数据
本次查询的时间范围数据为2023-09-25T19:47:44Z,查询的步长为9秒,共查询了593种指标,共写入7386695行数据
本次查询的时间范围数据为2023-09-25T19:48:14Z,查询的步长为10秒,共查询了593种指标,共写入7019614行数据
本次查询的时间范围数据为2023-09-25T19:48:44Z,查询的步长为5秒,共查询了593种指标,共写入9267445行数据
本次查询的时间范围数据为2023-09-25T19:49:37Z,查询的步长为55秒,共查询了593种指标,共写入5840872行数据
本次查询的时间范围数据为2023-09-25T19:50:40Z,查询的步长为15秒,共查询了593种指标,共写入4990036行数据
本次查询的时间范围数据为2023-09-25T19:54:53Z,查询的步长为15秒,共查询了593种指标,共写入5005466行数据

求助智障

以下是和人工智障的对话内容

本次查询的时间范围数据为2023-09-25T19:28:22Z,查询的步长为5秒,共查询了593种指标,共写入9265448行数据
本次查询的时间范围数据为2023-09-25T19:29:41Z,查询的步长为10秒,共查询了593种指标,共写入7027362行数据
本次查询的时间范围数据为2023-09-25T19:31:04Z,查询的步长为6秒,共查询了593种指标,共写入10554827行数据
本次查询的时间范围数据为2023-09-25T19:31:40Z,查询的步长为12秒,共查询了593种指标,共写入5942033行数据
本次查询的时间范围数据为2023-09-25T19:32:14Z,查询的步长为60秒,共查询了593种指标,共写入6093494行数据
本次查询的时间范围数据为2023-09-25T19:33:08Z,查询的步长为30秒,共查询了593种指标,共写入4305816行数据
本次查询的时间范围数据为2023-09-25T19:33:39Z,查询的步长为15秒,共查询了593种指标,共写入4897653行数据
本次查询的时间范围数据为2023-09-25T19:34:03Z,查询的步长为45秒,共查询了593种指标,共写入5551486行数据
本次查询的时间范围数据为2023-09-25T19:37:27Z,查询的步长为55秒,共查询了593种指标,共写入5826733行数据
本次查询的时间范围数据为2023-09-25T19:38:07Z,查询的步长为6秒,共查询了593种指标,共写入10711991行数据

————————————

根据我提供给你的代码,相信你已经知道了我这个代码是在干什么,我现在统计了当step为不同值时,查询所得到的数据的总行数上,已知查询的一直是同一个prometheus的同一个时间序列,请你帮我分析一下这个行数和step的规律

根据你提供的数据,可以看出不同的step值对查询结果的总行数产生了影响。总行数随着step值的不同而变化,这是因为step决定了查询的数据粒度,较小的step值会生成更多的数据点,因此总行数会增加。

根据你提供的数据和代码,可以总结一些规律:

  1. 较小的step值会生成更多的数据点,导致总行数增加。
  2. 较大的step值会生成较少的数据点,导致总行数减少。
  3. 不同的时间范围和step值组合也会影响总行数,时间范围越大,总行数越多,step越小,总行数也越多。

总之,总行数与step值、时间范围以及查询的具体指标有关。你可以根据实际需求选择合适的step值来平衡数据的粒度和查询结果的大小。较小的step值通常用于需要更详细数据的情况,而较大的step值可以减少数据量,提高查询效率。

本次查询的时间范围数据为2023-09-25T19:46:03Z,查询的步长为5秒,共查询了593种指标,共写入9281524行数据
本次查询的时间范围数据为2023-09-25T19:46:32Z,查询的步长为6秒,共查询了593种指标,共写入10808191行数据
本次查询的时间范围数据为2023-09-25T19:46:57Z,查询的步长为7秒,共查询了593种指标,共写入9272944行数据
本次查询的时间范围数据为2023-09-25T19:47:22Z,查询的步长为8秒,共查询了593种指标,共写入8113585行数据
本次查询的时间范围数据为2023-09-25T19:47:44Z,查询的步长为9秒,共查询了593种指标,共写入7386695行数据
本次查询的时间范围数据为2023-09-25T19:48:14Z,查询的步长为10秒,共查询了593种指标,共写入7019614行数据
本次查询的时间范围数据为2023-09-25T19:48:44Z,查询的步长为5秒,共查询了593种指标,共写入9267445行数据
本次查询的时间范围数据为2023-09-25T19:49:37Z,查询的步长为55秒,共查询了593种指标,共写入5840872行数据
本次查询的时间范围数据为2023-09-25T19:50:40Z,查询的步长为15秒,共查询了593种指标,共写入4990036行数据
本次查询的时间范围数据为2023-09-25T19:54:53Z,查询的步长为15秒,共查询了593种指标,共写入5005466行数据

————————————

你看这是我现在把各种exporter停掉之后的测试数据,也就是说现在基本是没有数据新增和变动了,但是现在的测试结果非常有趣了,我的prometheus的数据是每秒采集一次,也就是说你可以想象成这是一条连续的线,我的测试结果中,步长为15反而比步长为55的数据量更小?步长越大,数据量不是应该越小吗?

你提出的问题很有趣,步长越大,理论上查询的数据点数量应该越少,但根据你的测试结果,步长为15的情况下数据量小于步长为55的情况,这确实令人困惑。

要理解这个现象,我们需要考虑更多因素,包括Prometheus的内部工作机制和数据采集频率。步长越小,查询的数据点越多,因为Prometheus的数据存储通常会包含更多的数据点,这是为了提供更高的数据分辨率。但是步长变大后,查询时可能会进行数据降采样,以保持查询的响应速度,这可能会导致实际返回的数据点数量减少。

步长的选择通常取决于查询的目的。较小的步长适用于需要更详细数据的情况,而较大的步长适用于需要更高性能和较少数据点的情况。在步长较大的情况下,Prometheus可能会根据一些策略来降采样数据,以加速查询过程。

如果你想要更深入地理解这个现象,可以考虑查看Prometheus的配置和文档,以了解它在数据存储和查询方面的工作原理。此外,可以尝试不同的查询和步长组合,以获得更多关于查询性能和数据量之间的关系的见解。

在停掉了各种exporter后,相同的步长参数15秒,相隔仅仅4分钟5005466-4990036 =15,430还是新增了一万多(怎么突然想起来新冠新增人数了,不好意思这是错误记忆。)至于GPT说的降采集我感觉是在胡扯,但是我也说不出究竟是为什么。

(我想通了,原来我才是智障,自己写的代码,逻辑都给忘了,因为我前面设置了,根据步长来计算能够查询的小时数,在Prometheus的API上限尽可能多的获取数据,也就是步长变大,我的小时数是增加了的,小时数增加了,所以就不可能是理想的负相关!!!)