介绍实验性 info() 函数

2025年12月16日作者 Arve Knudsen

在 Prometheus 中,用元数据标签丰富指标可能出乎意料地棘手,即使您是 PromQL 达人!传统上用于此目的的 PromQL 连接查询本质上相当复杂,因为它必须指定要连接的标签、要连接的 info 指标以及要丰富使用的标签。新的、仍处于实验阶段的 info() 函数提供了一种更简单的方法,使标签丰富就像将查询包装在一个函数调用中一样简单。

在 Prometheus 3.0 中,我们引入了 info() 函数,这是一种丰富您的时间序列以及来自 info 指标的标签的强大新方法。与传统的连接查询技术相比,info() 的特别之处在于它使您不必指定标识性标签、要连接的 info 指标以及要丰富使用的(“数据”或“非标识性”)标签。请注意,“标识性标签”在此特定上下文中指的是用于标识相关 info 指标的标签集,并且这些标签与关联的非 info 指标共享。它们是您在 Prometheus 连接查询  中会用来连接的标签。概念上,它们可以与关系数据库中的外键 进行比较。

除了主要功能之外,info() 还解决了困扰连接查询多年的一个微妙但至关重要的问题:“抖动问题”,该问题会导致在非标识性 info 指标标签发生更改(如 OTLP 摄取那样缺少陈旧性标记)时查询失败。

无论您是处理 OpenTelemetry 资源属性、Kubernetes 标签还是其他任何元数据,info() 函数都能使您的 PromQL 查询更简洁、更可靠、更易于理解。

问题:复杂的连接和抖动问题

让我们先看看我们迄今为止所做的工作。假设您正在通过 OpenTelemetry 监控 HTTP 请求持续时间,并想按 Kubernetes 集群进行细分。您将指标推送到 Prometheus 的 OTLP 端点。您的指标具有 jobinstance 标签,但集群名称位于单独的 target_info 指标中,作为 k8s_cluster_name 标签。传统方法看起来是这样的:

sum by (http_status_code, k8s_cluster_name) (
    rate(http_server_request_duration_seconds_count[2m])
  * on (job, instance) group_left (k8s_cluster_name)
    target_info
)

虽然这可以工作,但存在几个问题:

1. 复杂性:您需要知道

  • 哪个 info 指标包含您的标签(target_info
  • 哪些标签是用于连接的“标识性”标签(jobinstance
  • 您想添加的数据标签(k8s_cluster_name
  • 正确的 PromQL 连接语法(ongroup_left

这需要专家级的 PromQL 知识,并使查询更难阅读和维护。

2. 抖动问题(关键问题)

这是一个微妙但严重的问题:当 OTel 资源属性在 Kubernetes 容器中更改,而标识性资源属性保持不变时会发生什么?一个例子是资源属性 k8s.pod.labels.app.kubernetes.io/version。然后,相应的 target_info 标签 k8s_pod_labels_app_kubernetes_io_version 会发生变化,Prometheus 会看到一个全新的 target_info 时间序列。

由于 OTLP 端点不会将旧的 target_info 系列标记为过时,因此在最多 5 分钟(默认回溯增量)内,旧的和新的系列可能会同时存在。在此重叠期间,您的连接查询会找到两个不同的匹配 target_info 时间序列,并因“多对多匹配”错误而失败。

实际上,这可能意味着当基础设施发生变化时,您的仪表板会中断,您的警报会停止触发,而此时您可能最需要可见性。

Info 函数提供解决方案

前面的连接查询可以转换为使用 info 函数,如下所示:

sum by (http_status_code, k8s_cluster_name) (
  info(rate(http_server_request_duration_seconds_count[2m]))
)

是不是更易于理解了?关于解决抖动问题,真正的魔力在于幕后:info() 自动选择具有最新样本的时间序列,从而完全消除了与抖动相关的连接失败。请注意,此 info() 调用返回 target_info 的所有数据标签,但这并不重要,因为我们使用 sum 将它们聚合掉。

基本语法

info(v instant-vector, [data-label-selector instant-vector])
  • v:要用元数据标签丰富即时向量
  • data-label-selector(可选):用花括号括起来的标签匹配器,用于过滤要包含的标签

在其最基本的形式下,省略第二个参数,info() 添加 target_info所有数据标签。

info(rate(http_server_request_duration_seconds_count[2m]))

另一方面,通过第二个参数,您可以控制要包含在 target_info 中的数据标签。

info(
  rate(http_server_request_duration_seconds_count[2m]),
  {k8s_cluster_name=~".+"}
)

在上面的示例中,info() 包含了 target_info 中的 k8s_cluster_name 数据标签。因为选择器匹配任何非空字符串,所以它将包含任何 k8s_cluster_name 标签值。

也可以过滤要包含的 k8s_cluster_name 标签值。

info(
  rate(http_server_request_duration_seconds_count[2m]),
  {k8s_cluster_name="us-east-0"}
)

选择不同的 Info 指标

默认情况下,info() 使用 target_info 指标。但是,您可以通过在 data-label-selector 中包含 __name__ 匹配器来选择不同的 info 指标(如 build_infonode_uname_info)。

# Use build_info instead of target_info
info(up, {__name__="build_info"})

# Use multiple info metrics (combines labels from both)
info(up, {__name__=~"(target|build)_info"})

# Select build_info and only include the version label
info(up, {__name__="build_info", version=~".+"})

注意:当前实现始终使用 jobinstance 作为连接的标识性标签,无论您选择哪个 info 指标。这对于大多数标准的 info 指标效果很好,但对于使用不同标识性标签的自定义 info 指标可能存在限制。一个示例是 kube_pod_labels,它的标识性标签是:namespacepod。意图是 info() 在未来能够识别 TSDB 中的哪些指标是 info 指标,并自动使用所有这些指标,除非通过名称匹配器(如上)明确限制了选择,并且这些是每个 info 指标的标识性标签。

实际用例

OpenTelemetry 集成

info() 函数的主要驱动因素是 OpenTelemetry (OTel) 集成。当使用 Prometheus 作为 OTel 后端时,资源属性(关于指标生产者的元数据)会自动转换为 target_info 指标。

  • service.instance.idinstance 标签
  • service.namejob 标签
  • service.namespace → 前缀添加到 job(例如,<namespace>/<service.name>
  • 所有其他资源属性 → target_info 上的数据标签

这意味着,只要包含至少一个 service.instance.idservice.name 资源属性,您通过 OTLP 发送到 Prometheus 的每个 OTel 指标都可以使用 info() 进行资源属性丰富。

# Add all OTel resource attributes
info(rate(http_server_request_duration_seconds_sum[5m]))

# Add only specific attributes
info(
  rate(http_server_request_duration_seconds_sum[5m]),
  {k8s_cluster_name=~".+", k8s_namespace_name=~".+", k8s_pod_name=~".+"}
)

构建信息

用构建时信息丰富您的指标。

# Add version and branch information to request rates
sum by (job, http_status_code, version, branch) (
  info(
    rate(http_server_request_duration_seconds_count[2m]),
    {__name__="build_info"}
  )
)

按生产者版本过滤

仅选择来自特定生产者版本的指标。

sum by (job, http_status_code, version) (
  info(
    rate(http_server_request_duration_seconds_count[2m]),
    {__name__="build_info", version=~"2\\..+"}
  )
)

前后对比:并排比较

让我们看看 info() 函数如何简化实际查询。

示例 1:OpenTelemetry 资源属性丰富

传统方法

sum by (http_status_code, k8s_cluster_name, k8s_namespace_name, k8s_container_name) (
    rate(http_server_request_duration_seconds_count[2m])
  * on (job, instance) group_left (k8s_cluster_name, k8s_namespace_name, k8s_container_name)
    target_info
)

使用 info()

sum by (http_status_code, k8s_cluster_name, k8s_namespace_name, k8s_container_name) (
  info(rate(http_server_request_duration_seconds_count[2m]))
)

使用 info,意图更加清晰:我们正在用与 Kubernetes 相关的 OpenTelemetry 资源属性丰富 http_server_request_duration_seconds_count

示例 2:按标签值过滤

传统方法

sum by (http_status_code, k8s_cluster_name) (
    rate(http_server_request_duration_seconds_count[2m])
  * on (job, instance) group_left (k8s_cluster_name)
    target_info{k8s_cluster_name=~"us-.*"}
)

使用 info()

sum by (http_status_code, k8s_cluster_name) (
  info(
    rate(http_server_request_duration_seconds_count[2m]),
    {k8s_cluster_name=~"us-.*"}
  )
)

在这里,我们过滤以仅包含来自美国(名称以 us- 开头)的集群的指标。info() 版本将过滤器自然地集成到 data-label-selector 中。

技术优势

除了基本的 UX 优势外,info() 函数还提供了几项技术优势:

1. 自动抖动处理

如前所述,当存在多个版本时,info() 会自动选择具有最新样本的匹配 info 时间序列。这消除了在抖动期间困扰传统连接查询的“多对多匹配”错误。

工作原理:当非标识性 info 指标标签发生更改时(例如,Pod 被重新创建),会有一个短暂的时期,旧的和新的系列都可能存在。info() 函数只需选择具有最新样本的那个,即可确保您的查询继续正常工作。

2. 更好的性能

info() 函数比传统连接更有效。

  • 仅选择匹配的 info 系列
  • 避免不必要的标签匹配操作
  • 优化的查询执行路径

入门

info() 函数是实验性的,必须通过功能标志启用。

prometheus --enable-feature=promql-experimental-functions

启用后,您可以立即开始使用它。

当前限制和未来计划

当前实现是一个MVP(最小可行产品),旨在验证方法并收集用户反馈。该实现存在一些有意限制:

当前限制

  1. 默认 info 指标:默认仅考虑 target_info

    • 解决方法:您可以在 data-label-selector 中使用 __name__ 匹配器,如 {__name__=~"(target|build)_info"},尽管这仍然假定 jobinstance 是标识性标签。
  2. 固定的标识性标签:始终假定 jobinstance 是连接的标识性标签。

    • 这不幸地使得 info() 不适用于某些场景,例如,包含来自 kube_pod_labels 的数据标签,但这是我们将来想解决的问题。

未来发展

这些限制是暂时的。实验状态允许我们:

  • 收集实际使用反馈
  • 了解哪些用例最重要
  • 在承诺最终 API 之前进行迭代

info() 函数的未来版本应:

  • 默认考虑所有 info 指标(不只是 target_info
  • 根据 info 指标元数据自动理解标识性标签

重要提示:由于这是一个实验性功能,行为可能会在将来的 Prometheus 版本中发生更改,或者根据用户反馈,该函数可能会从 PromQL 中完全删除。

提供反馈

您的反馈将直接塑造此功能的未来,并帮助我们确定它是否应成为 PromQL 的永久组成部分。可以通过我们的社区连接或通过打开一个Prometheus issue  来提供反馈。

我们鼓励您尝试 info() 函数并分享您的反馈。

  • 它为您解决了哪些用例?
  • 您希望看到哪些额外功能?
  • API 如何改进?
  • 您是否看到了性能提升?

结论

实验性 info() 函数代表了使 PromQL 更易于访问和可靠的重大进步。通过简化元数据标签丰富和自动处理抖动问题,它消除了 Prometheus 用户(尤其是那些采用 OpenTelemetry 的用户)的两个主要痛点。

了解更多

请随时通过我们的GitHub Discussions  或在 CNCF Slack #prometheus 频道  上与 Prometheus 社区联系。

祝您查询愉快!