Prometheus 联邦模式踩坑记:从指标抓取不全到函数计算的“坑”
在实际的运维工作中,我们经常需要对分散在不同服务器上的服务进行统一的监控和指标收集。Prometheus 提供了联邦模式(Federation)来应对这种场景,允许我们将多个独立的 Prometheus Server(称为下游 Prometheus)的指标聚合到一个上层 Prometheus Server 上。这篇博客将记录我在配置 Prometheus 联邦模式过程中遇到的几个关键问题,以及如何一步步解决它们。
背景:搭建联邦模式监控
我们的目标是构建一个统一的监控平台,将多台服务器上的 node-exporter 指标,通过两级 Prometheus Server 进行采集和聚合。具体架构如下:
- 下游 Prometheus Server (server32, server33): 各自负责抓取所在节点上的
node-exporter指标。 - 上游 Prometheus Server (server31): 负责从下游 Prometheus Server(server32, server33)联邦(fetch)这些指标数据。
坑点一:联邦模式下的指标匹配问题
现象: 在配置好下游 Prometheus Server (server32, server33) 抓取 node-exporter 指标后,我们在上游 Prometheus Server (server31) 上配置了联邦作业,期望能够抓取到 node-exporter 的各项指标。然而,在上游 Server 的 /targets 页面,联邦作业显示正常,但在查询 node_cpu_seconds_total 等指标时,却发现数据为空。
分析: 联邦模式的配置核心在于 params.match[] 字段,它定义了上游 Prometheus 需要从下游 Prometheus 拉取哪些指标。如果这里的匹配规则不正确,即使抓取作业本身是 UP 的,也无法获取到期望的数据。
我们最初的配置可能存在如下问题:
- 拼写错误: 在配置抓取自身 Prometheus 指标时,可能出现了
job="promethues"的拼写错误,应为job="prometheus"。 - 匹配规则不精确: 使用
'{__name__=~"job:.*"}'这样的规则,是基于指标名称(__name__)来匹配的。而node-exporter的指标名称(如node_cpu_seconds_total)并不会以job:开头。这导致该规则无法匹配到node-exporter的指标。
解决方案:
- 修正拼写错误: 将所有
'{job="promethues"}'改为'{job="prometheus"}'。 - 精准匹配下游 Job: 最有效的方式是直接匹配下游 Prometheus Server 上定义了的
job_name。例如,如果 server32 的job_name是oldboyedu-file-service-discovery-32,那么匹配规则应为'{job="oldboyedu-file-service-discovery-32"}'。 - 利用 Job 标签的正则表达式匹配: 当下游有多个 Prometheus Server 且它们的
job_name有规律时(例如都以oldboyedu-file-service-discovery-开头),可以使用正则表达式进行匹配,例如'{job=~"oldboyedu-file-service-discovery-.*"}'。这比单独列出每个 job 更方便。 - 配合
__name__匹配: 如果想抓取所有node-exporter的指标,可以再补充'{__name__=~"node.*"}'的规则。
修正后的联邦配置示例(在 server31 上):
scrape_configs:
- job_name: 'prometheus-federate-32'
metrics_path: "/federate"
honor_labels: true
params:
"match[]":
- '{job="prometheus"}' # 匹配上游自身指标
- '{job="oldboyedu-file-service-discovery-32"}' # 精确匹配 server32 的 job
- '{__name__=~"node.*"}' # 匹配所有以 node 开头的指标
static_configs:
- targets:
- "10.0.0.32:9090"
- job_name: 'prometheus-federate-33'
metrics_path: "/federate"
honor_labels: true
params:
"match[]":
- '{job="prometheus"}'
- '{job="oldboyedu-file-service-discovery-33"}' # 精确匹配 server33 的 job
- '{__name__=~"node.*"}'
static_configs:
- targets:
- "10.0.0.33:9090"
坑点二:函数计算的“延迟”与网络瓶颈
现象: 在成功获取到 node_cpu_seconds_total 指标后,我们在上游 Prometheus Server (server31) 上尝试查询 increase(node_cpu_seconds_total{cpu="0",mode="idle"}[1m]),发现数据为空或不准确,但查询 increase(node_cpu_seconds_total{cpu="0",mode="idle"}[1h]) 却可以正常工作。
分析: Prometheus 的函数(如 increase, rate)依赖于连续的数据点来计算。函数的计算精度与抓取间隔直接相关。
- Prometheus 的抓取间隔: 默认是 15 秒。这意味着 Prometheus 每 15 秒会抓取一次新的数据点。
- 联邦抓取的实际间隔: 当进行联邦抓取时,上游 Prometheus (server31) 实际上是以自己的
scrape_interval(默认 15 秒)去向下游 Prometheus (server32,server33) 发起请求。 - 网络延迟的影响: 如果下游 Prometheus 位于远端 VM 上,那么上游 Prometheus 发起抓取请求到收到响应的整个过程会受到网络延迟的影响。
- 数据点间隔增大: 高网络延迟会导致上游 Prometheus 实际获取到下游数据点的时间间隔大于其自身的
scrape_interval。 - 函数计算受阻:
increase(..., [1m])需要在 1 分钟内获取到至少 2 个(更精确地说,基于 15 秒抓取间隔,至少需要 4 个)数据点才能准确计算。如果网络延迟导致实际数据点间隔大于 15 秒(例如变成了 20-30 秒),那么在 1 分钟内可能就只有 2-3 个数据点,不足以满足计算要求。 increase(..., [1h])则需要非常多的数据点,即使有网络延迟,在 1 小时内通常也能累积足够的数据点,因此可以正常工作。
- 数据点间隔增大: 高网络延迟会导致上游 Prometheus 实际获取到下游数据点的时间间隔大于其自身的
解决方案:
- 优化网络连接: 这是最根本的解决方法。尽量缩短上游 Prometheus 与下游 Prometheus 之间的网络延迟,提高网络带宽和稳定性。
- 调整上游 Prometheus 的
scrape_interval: 如果网络延迟不可避免,可以考虑缩短上游 Prometheus 的抓取间隔(例如从默认的 15 秒缩短到 5 秒或 10 秒),以增加数据获取的频率,提高数据的时效性和连续性。- 修改
prometheus-server31的prometheus.yml文件中的global.scrape_interval参数。
- 修改
- 验证原始指标数据: 在上游 Prometheus Server (server31) 上,直接查询
node_cpu_seconds_total{cpu="0",mode="idle"},查看返回的数据点之间的时间间隔。如果间隔大于 15 秒,则说明是网络延迟导致的问题。
总结
通过这次实践,我们深入理解了 Prometheus 联邦模式的配置要点以及它在实际网络环境中的行为。关键在于:
- 准确的
match[]规则: 理解__name__和job标签的区别,使用 Job 名称或其正则表达式进行精准匹配。 - 网络延迟的影响: 联邦模式的抓取频率受上游 Prometheus 的
scrape_interval控制,但实际数据的新鲜度和连续性受制于网络延迟。 - 函数计算与数据点:
increase等函数需要连续的数据点,网络延迟可能导致数据点间隔增大,影响短时间范围内的函数计算。
通过这次踩坑和排查,我们不仅解决了指标抓取的问题,也对 Prometheus 的工作机制有了更深刻的认识。希望这篇博客能为同样在实践 Prometheus 联邦模式的同学们提供一些参考和帮助。
浙公网安备 33010602011771号