记一次Prometheus的离奇经历

前情提要 书接上回,为了获取客户的 Prometheus 监控数据,我写了个脚本用来通过 API 获取监控数据,然后转换成 OpenMetrics 格式以方便传输和导入,代码如下。 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-25 · 11 min

获取客户 Prometheus 监控数据

业务背景 在排查问题时,想通过 Grafana 看板查看用户的监控,只能靠拍照,效率低,质量一般。设计一个方案能够方便地将问题出现前 24 小时的监控数据拿到,在本地导入,就能够在本地 Grafana 方便地查看。Prometheus 本身只提供了 API 查询的功能,并没有导出数据功能;自带的 promtool 也只提供验证规则文件和配置文件、调试等功能。 参考文章 Analyzing Prometheus data with external tools Prometheus backfilling 方案一:使用 API 导出转换成 CSV 使用 API 查询,将查询到的数据转换成 CSV。刚好 Grafana 有插件能够将 CSV 作为数据源。经过实验后并不是特别顺利,能够读取到 CSV,但没有成功绘制出图像。 总结 经过实验后并不是特别顺利,能够读取到 CSV 但没有成功绘制出图像。看板中部分查询语句中包含看板变量,CSV 数据源无法实现看板变量。 方案二:拷贝 Prometheus 数据文件 Prometheus 按照两个小时为一个时间窗口,将两小时内产生的数据存储在一个块(Block)中。每个块都是一个单独的目录,里面包含该时间窗口内的所有样本数据(chunks)、元数据文件(meta.json)以及索引文件(index)。其中索引文件会将指标名称和标签索引到样本数据的时间序列中。此期间如果通过 API 删除时间序列,删除记录会保存在单独的逻辑文件 tombstone 当中。 Prometheus 为了防止丢失暂存在内存中的还未被写入磁盘的监控数据,引入了 WAL 机制。WAL 被分割成默认大小为 128M 的文件段(segment),之前版本默认大小是 256M,文件段以数字命名,长度为 8 位的整型。WAL 的写入单位是页(page),每页的大小为 32KB,所以每个段大小必须是页的大小的整数倍。如果 WAL 一次性写入的页数超过一个段的空闲页数,就会创建一个新的文件段来保存这些页,从而确保一次性写入的页不会跨段存储。这些数据暂时没有持久化,TSDB 通过 WAL 将数据保存到磁盘上(保存的数据没有压缩,占用内存较大),当出现宕机时,启动多协程读取 WAL,恢复数据。 [mingming.chen@m162p65 data]$ tree . ├── 01E2MA5GDWMP69GVBVY1W5AF1X │ ├── chunks # 保存压缩后的时序数据,每个 chunks 大小为 512M,超过会生成新的 chunks │ │ └── 000001 │ ├── index # chunks 中的偏移位置 │ ├── meta.json # 记录 block 块元信息,比如样本的起始时间、chunks 数量和数据量大小等 │ └── tombstones # 通过 API 方式对数据进行软删除,将删除记录存储在此处(API 的删除方式,并不是立即将数据从 chunks 文件中移除) ├── 01E2MH175FV0JFB7EGCRZCX8NF │ ├── chunks │ │ └── 000001 │ ├── index │ ├── meta.json │ └── tombstones ├── 01E2MQWYDFQAXXPB3M1HK6T20A │ ├── chunks │ │ └── 000001 │ ├── index │ ├── meta.json │ └── tombstones ├── lock ├── queries.active └── wal # 防止数据丢失(数据收集上来暂时是存放在内存中,wal 记录了这些信息) ├── 00000366 # 每个数据段最大为 128M,存储默认存储两个小时的数据量 ├── 00000367 ├── 00000368 ├── 00000369 └── checkpoint.000365 └── 00000000 无论是 block 数据还是 wal 数据,都是可以直接打包,转移到本地的 Prometheus。需要注意的是版本问题,且本地 Prometheus 不能有数据。如果本地监控数据目录不为空,那么导入时会出现问题(因为时间问题)。只需要近期数据,太远的数据没有价值,可以通过 block 文件里面的 meta.json 查看时间戳。 ...

2023-09-08 · 17 min

Docker 运行 VictoriaMetrics 测试体验

VictoriaMetrics 是一个开源的、快速的、低成本的时间序列数据库和监测系统。它最初是由俄罗斯 IT 公司 “Badoo” 的一个工程师团队开发的,以满足他们的监测需求。然而,它后来被作为开源软件发布,供更广泛的社区使用。VictoriaMetrics 被设计用来处理大量的时间序列数据,同时保持高性能和可扩展性。它使用一个定制的存储引擎,优化时间序列数据的存储,并实现快速查询和聚合。除了时间序列数据库的功能,VictoriaMetrics 还包括一个监控系统,可以从各种来源收集和可视化指标,包括 Prometheus、Graphite 和 InfluxDB。VictoriaMetrics 与流行的查询语言兼容,包括 PromQL 和 Graphite,并可以作为独立的二进制文件、Docker 容器或 Kubernetes 操作器部署。总的来说,VictoriaMetrics 是一个强大而灵活的工具,用于管理时间序列数据和监测系统性能,使其成为许多组织的热门选择。 ...

2023-03-16 · 5 min

Minikube 中使用 Helm 安装 Prometheus 监控大全套

Minikube is a tool that allows you to run a Kubernetes cluster on your local machine. It is designed to make it easy to develop and test applications that will be deployed to a production Kubernetes environment. Minikube runs a single-node Kubernetes cluster inside a virtual machine on your local machine, which allows you to simulate a real-world Kubernetes environment without the need for additional hardware. ...

2023-03-15 · 6 min

使用 prometheus_client 写一个 exporter

在使用 Filebeat 收集系统日志时,有些网络设备的日志是通过 UDP 端口接收的,并且有多个 Filebeat 实例在使用不同的 UDP 端口同时运行。为了保证日志的完整性,避免因 Filebeat 意外停止导致数据丢失,需要监控其运行状态。首先想到的是 process_exporter,但在调研后发现,它对同名多个进程的监控配置较为复杂,难以满足需求。另一个方案是使用 blackbox_exporter 监控 Filebeat 所用端口,但深入研究后发现 blackbox_exporter 并不支持 UDP 端口探测。于是决定自己动手写一个 exporter。 ...

2023-02-07 · 4 min

Alertmanager + Grafana 安装及配置服务

The Alertmanager handles alerts sent by client applications such as the Prometheus server. It takes care of deduplicating, grouping, and routing them to the correct receiver integration such as email, PagerDuty, or OpsGenie. It also takes care of silencing and inhibition of alerts. Grafana allows you to query, visualize, alert on and understand your metrics no matter where they are stored. Create, explore, and share beautiful dashboards with your team and foster a data driven culture. ...

2022-04-09 · 1 min

用 Docker Compose 部署一套 Prometheus 监控系统

Prometheus 受启发于 Google 的 Borgmon 监控系统(相似的 Kubernetes 是从 Google 的 Borg 系统演变而来),从 2012 年开始由前 Google 工程师在 SoundCloud 以开源软件的形式进行研发,并且于 2015 年早期对外发布早期版本。2016 年 5 月继 Kubernetes 之后成为第二个正式加入 CNCF 基金会的项目,同年 6 月正式发布 1.0 版本。2017 年底发布了基于全新存储层的 2.0 版本,能更好地与容器平台、云平台配合。 ...

2021-12-20 · 1 min