介绍实验性 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 端点。您的指标具有 job 和 instance 标签,但集群名称位于单独的 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) - 哪些标签是用于连接的“标识性”标签(
job、instance) - 您想添加的数据标签(
k8s_cluster_name) - 正确的 PromQL 连接语法(
on、group_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_info 或 node_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=~".+"})
注意:当前实现始终使用 job 和 instance 作为连接的标识性标签,无论您选择哪个 info 指标。这对于大多数标准的 info 指标效果很好,但对于使用不同标识性标签的自定义 info 指标可能存在限制。一个示例是 kube_pod_labels,它的标识性标签是:namespace 和 pod。意图是 info() 在未来能够识别 TSDB 中的哪些指标是 info 指标,并自动使用所有这些指标,除非通过名称匹配器(如上)明确限制了选择,并且这些是每个 info 指标的标识性标签。
实际用例
OpenTelemetry 集成
info() 函数的主要驱动因素是 OpenTelemetry (OTel) 集成。当使用 Prometheus 作为 OTel 后端时,资源属性(关于指标生产者的元数据)会自动转换为 target_info 指标。
service.instance.id→instance标签service.name→job标签service.namespace→ 前缀添加到job(例如,<namespace>/<service.name>)- 所有其他资源属性 →
target_info上的数据标签
这意味着,只要包含至少一个 service.instance.id 或 service.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(最小可行产品),旨在验证方法并收集用户反馈。该实现存在一些有意限制:
当前限制
-
默认 info 指标:默认仅考虑
target_info。- 解决方法:您可以在
data-label-selector中使用__name__匹配器,如{__name__=~"(target|build)_info"},尽管这仍然假定job和instance是标识性标签。
- 解决方法:您可以在
-
固定的标识性标签:始终假定
job和instance是连接的标识性标签。- 这不幸地使得
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 社区联系。
祝您查询愉快!