ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Prometheus 日常巡检:抓住采集延迟、基数和规则错误

2026/8/16 9:00:21 拓冰建站 浏览量
Prometheus 日常巡检:抓住采集延迟、基数和规则错误

Prometheus 日常巡检:抓住采集延迟、基数和规则错误

Prometheus 巡检先看采集是否按时完成,再看标签基数和规则评估。图表正常不代表数据完整;Target 延迟、丢样和规则错误都要单独报警。阈值以当前环境基线为准。

1. Prometheus 性能劣化的根源:高基数标签与慢查询

日常巡检要优先处理以下三类监控问题:

  1. 高基数标签膨胀(High Cardinality Explosion):如果把user_idemailclient_ip或随机 UUID 写进 Label,时间序列数量会随取值基数快速增加,可能推高 TSDB Head Block 的内存与压缩开销。
  2. 长周期慢 PromQL 拖垮 TSDB 引擎:某些 Grafana 视图使用了形如rate(http_requests_total[30d])且未加 namespace 筛选的大范围查询,导致 Prometheus 内存很快爆表。
  3. 僵尸告警规则(Stale Alert Rules):已下线的服务配置依然保留在 PromQL 告警规则中,导致 Alertmanager 持续刷新脏计算开销。

2. 自动化巡检与治理流水线架构

为少走弯路,可以放弃了“人工定期点开 Grafana 检查”的传统做法,设计一套基于 Prometheus HTTP API 的自动化诊断与巡检机器人。


3. Prometheus 自动化巡检脚本实现

以下是用 Python 编写的 Prometheus TSDB 存储与高基数标签自动化巡检脚本。该脚本通过调用 Prometheus 官方 REST API,自动分析当前占用内存最大的前 10 个高基数指标,并生成巡检汇总。

#!/usr/bin/env python3 # -*- coding: utf-8 -*- import requests import json from typing import Dict, List class PrometheusHealthInspector: def __init__(self, prom_url: str): self.prom_url = prom_url.rstrip('/') def inspect_tsdb_cardinality(self) -> Dict: """调用 TSDB Status API,分析内存中高基数指标 Top 10""" url = f"{self.prom_url}/api/v1/status/tsdb" try: resp = requests.get(url, timeout=10) if resp.status_code != 200: return {"error": f"请求失败 HTTP {resp.status_code}"} data = resp.json().get("data", {}) head_stats = data.get("headStats", {}) series_count_by_metric = data.get("seriesCountByMetricName", []) label_value_count_by_name = data.get("labelValueCountByLabelName", []) return { "num_series": head_stats.get("numSeries", 0), "num_label_pairs": head_stats.get("numLabelPairs", 0), "top_cardinality_metrics": series_count_by_metric[:10], "top_cardinality_labels": label_value_count_by_name[:10] } except Exception as e: return {"error": str(e)} def inspect_unhealthy_targets(self) -> List[Dict]: """检查抓取失败或响应超时的 Target""" url = f"{self.prom_url}/api/v1/targets" unhealthy = [] try: resp = requests.get(url, timeout=10) if resp.status_code == 200: active_targets = resp.json().get("data", {}).get("activeTargets", []) for target in active_targets: if target.get("health") != "up": unhealthy.append({ "job": target.get("labels", {}).get("job", "unknown"), "instance": target.get("discoveredLabels", {}).get("__address__", "unknown"), "health": target.get("health"), "last_error": target.get("lastError", "") }) except Exception as e: print(f"检查 Target 异常: {e}") return unhealthy def generate_report(self) -> str: """生成 Markdown 格式的日常巡检报告""" tsdb_data = self.inspect_tsdb_cardinality() unhealthy_targets = self.inspect_unhealthy_targets() md = "# Prometheus 监控体系日常自动化巡检报告\n\n" if "error" in tsdb_data: md += f"❌ **TSDB 状态获取异常**: {tsdb_data['error']}\n" return md md += "## 一、 TSDB 内存与时间序列概览\n\n" md += f"- **当前内存 Head Block 时间序列总数 (numSeries)**: `{tsdb_data['num_series']:,}`\n" md += f"- **当前内存 Label Pair 总数**: `{tsdb_data['num_label_pairs']:,}`\n\n" md += "### ⚠️ 高基数指标 Top 10 (基数过高易引发 OOM)\n\n" md += "| Metric 名称 | 时间序列数量 (Series Count) |\n" md += "|-------------|-----------------------------|\n" for item in tsdb_data["top_cardinality_metrics"]: md += f"| `{item['name']}` | `{item['value']:,}` |\n" md += "\n## 二、 不健康 Target 抓取节点\n\n" if unhealthy_targets: md += f"发现 `{len(unhealthy_targets)}` 个 Down 状态节点:\n\n" md += "| Job | Instance Address | 错误详情 |\n" md += "|-----|------------------|----------|\n" for target in unhealthy_targets: md += f"| `{target['job']}` | `{target['instance']}` | {target['last_error']} |\n" else: md += "✅ 所有配置的 Metrics 抓取 Target 状态均正常 (UP)。\n" return md if __name__ == "__main__": inspector = PrometheusHealthInspector("http://localhost:9090") print(inspector.generate_report())

4. 诊断工具与排障命令组合拳

在巡检过程中发现 Prometheus TSDB 占用内存过高或慢查询时,运维人员应当使用以下工具迅速诊断并下手清理。

1. 现场诊断 Prometheus 内核元数据 API

# 1. 极速查询 TSDB 存储引擎元数据,列出全站前 10 个高基数指标 curl -s http://localhost:9090/api/v1/status/tsdb | jq '.data.seriesCountByMetricName[0:10]' # 2. 查询当前占用内存最多、数值变化最频繁的 Label 名称 curl -s http://localhost:9090/api/v1/status/tsdb | jq '.data.labelValueCountByLabelName[0:10]' # 3. 统计过去 1 小时内抓取产生 Samples 最多的 Job curl -s http://localhost:9090/api/v1/query?query='topk(10, count by (job) ({__name__=~".+"}))' | jq .

2. 通过 Prometheus Relabeling 确定性裁剪脏标签

如果在巡检中发现http_requests_total中包含大量脏标签user_id,可以直接在抓取配置中加硬拦截策略:

# prometheus.yml scrape_configs: - job_name: 'api-service' kubernetes_sd_configs: - role: pod metric_relabel_configs: # 强行删除包含高基数用户 ID 的危险 Label - action: labeldrop regex: "user_id|client_ip|device_uuid" # 将高频变化的动态路径收敛为统一占位符 - source_labels: [path] regex: "/api/v1/user/[0-9]+" target_label: path replacement: "/api/v1/user/:id"

5. 生产治理与架构调优收口

根据日常自动化巡检积累的数据,监控体系应当进行如下确定性收口:

日常巡检治理落地总结

验证这套治理组合时,先从 Prometheus 状态接口记录当前时间序列数,再用相同抓取配置比较以下指标:

  1. 巡检人力成本降至零:通过定时 CronJob 自动生成 Markdown 巡检报告并同步到钉钉/飞书群,运维工程师不再需要手动抓数据和拼接视图。

自动化脚本可以检查采集延迟、规则错误和标签基数。脚本自身也要有运行状态与报警,避免监控失效却无人发现。