你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

OpenTelemetry 指标的 PromQL 最佳做法

本文提供了在 Azure Monitor 中使用 Prometheus 查询语言(PromQL)查询 OpenTelemetry 指标的最佳做法。 OpenTelemetry 指标具有独特的特征,在编写 PromQL 查询时需要特定注意事项,尤其是围绕字符编码、指标命名和数据时态。

先决条件

Prometheus 和 OpenTelemetry 指标之间的主要区别

OpenTelemetry 指标不同于传统的 Prometheus 指标,这些指标以多种重要方式影响编写 PromQL 查询的方式:

指标命名和字符编码

OpenTelemetry 指标通常包含需要 PromQL 中特殊处理的字符:

  • 指标名称中的点:OpenTelemetry 在指标名称中使用点(.),例如 http.server.duration
  • 标签中的特殊字符:资源属性可能包含非字母数字字符。
  • UTF-8 编码:使用 Prometheus 3.0,完整的 UTF-8 支持使得无需字符转义即可执行查询。

数据模型差异

方面 Prometheus (旧版) OpenTelemetry
聚合时态性 仅限累积 累积或增量
直方图区间 带有 le 标签的显式存储桶 指数存储桶或显式存储桶
速率计算 始终使用 rate()increase() 取决于时态性
指标后缀 手动 (_total_bucket 基于仪器类型的自动

OpenTelemetry 指标的 UTF-8 字符转义

借助 Prometheus 3.0 的 UTF-8 支持,可以使用其原始名称直接查询 OpenTelemetry 指标:

# Direct querying with UTF-8 support using curly braces
{"http.server.duration"}

# Query with complex label names
{"process.runtime.jvm.memory.usage"}{
  "service.name"="my-service",
  "jvm.memory.type"="heap"
}

旧版 Prometheus 版本

对于较旧的 Prometheus 版本,请使用 __name__ 标签来查询具有特殊字符的指标:

# Using __name__ for metrics with dots
{__name__="http.server.duration"}

# Combining with other label selectors
{__name__="http.server.duration", job="my-app"}

常见的 OpenTelemetry 指标名称模式

OpenTelemetry 指标遵循通常包括点的 语义约定

# HTTP metrics
{"http.server.duration"}
{"http.client.request.size"}

# System metrics  
{"system.cpu.utilization"}
{"system.memory.usage"}

# Runtime metrics
{"process.runtime.jvm.memory.usage"}
{"process.runtime.go.gc.duration"}

处理聚合时态

查询 OpenTelemetry 指标时最关键的区别之一是了解聚合时态性。

累积时态

累积指标的工作方式类似于传统的 Prometheus 计数器,需要 速率计算

# For cumulative HTTP request counts
rate({"http.server.request.count"}[5m])

# For cumulative HTTP durations (histograms)
rate({"http.server.duration_sum"}[5m]) / 
rate({"http.server.duration_count"}[5m])

增量时间特性

增量指标表示自上次测量以来的变化,不应使用 rate()increase()

# For delta HTTP request counts - NO rate() needed
{"http.server.request.count"}

# For delta HTTP durations 
{"http.server.duration_sum"} / {"http.server.duration_count"}

确定时态性

遗憾的是,PromQL 无法自动检测时态性。 需要知道数据源:

  • Prometheus:通常发送累积指标
  • OpenTelemetry:混合,取决于 SDK 和配置
  • 自定义导出程序:检查导出程序文档

时间性最佳实践

  • 记录数据源:跟踪哪些指标使用哪个时态
  • 使用一致的命名:考虑向指标名称添加时态提示
  • 创建单独的仪表板:为累积指标和增量指标生成不同的视图
  • 测试查询:验证速率计算是否生成预期结果与原始值相比

直方图查询模式

OpenTelemetry 直方图可以使用不同的存储桶策略。 Azure Monitor 托管的 Prometheus 实现在不同直方图类型上提供了增强的直方图函数支持。

支持的直方图函数

功能 OTLP 显式直方图 Prometheus 原生直方图/OTLP 指数直方图 Prometheus 传统直方图
histogram_quantile histogram_quantile(0.9, sum by (cluster, le) (rate({"http.request.duration"}[5m])))
注意: le 是仅在查询期间存在的虚构标签
histogram_quantile(0.9, sum by (cluster) (rate({"http.request.duration"}[5m]))) histogram_quantile(0.9, sum by (cluster, le) (rate({"http.request.duration_bucket"}[5m])))
histogram_avg histogram_avg(rate({"http.request.duration"}[5m])) histogram_avg(rate({"http.request.duration"}[5m])) 不支持
histogram_count histogram_count(rate({"http.request.duration"}[5m])) histogram_count(rate({"http.request.duration"}[5m])) 不支持
histogram_sum histogram_sum(rate({"http.request.duration"}[5m])) histogram_sum(rate({"http.request.duration"}[5m])) 不支持
histogram_fraction 不支持 histogram_fraction(0, 0.2, rate({"http.request.duration"}[1h])) 不支持
histogram_stddev 不支持 已支持 不支持
histogram_stdvar 不支持 已支持 不支持

注释

Azure Monitor 的托管 Prometheus 提供了超越开源 Prometheus 的增强直方图支持。 处理 OTLP 显式直方图的所有直方图函数(histogram_avghistogram_counthistogram_sum)都是 Azure 特定的增强功能,目前在开源 Prometheus 中无法使用。 有关标准 Prometheus 直方图支持,请参阅 histogram_quantile

Azure Monitor 直方图实现详细信息

在 Azure Monitor 中查询直方图指标时,请记住以下性能注意事项:

  • 直方图指标上的非直方图函数:当将非直方图Functions 应用于直方图指标时,该函数仅对总和值进行操作,不会从数据存储中检索存储桶值。

  • 直方图查询成本:直方图函数查询的直方图指标的成本至少比正常计数器样本高出 10.5 倍。 在以下情况下,请考虑以下事项:

    • 对直方图数据执行长时间回溯
    • 在高基数指标上应用直方图函数
    • 设计可能接近查询限制阈值的查询

    在应用直方图函数之前,使用 记录规则 预先聚合和减少基数。

显式直方图(旧版兼容)

# Calculate percentiles from explicit buckets - requires 'le' in group by
histogram_quantile(0.99, 
  sum by ("service.name", le) (rate({"http.server.request.duration"}[2m]))
)

# 95th percentile without additional grouping dimensions
histogram_quantile(0.95,
  sum by (le) (rate({"http.server.duration_bucket"}[5m]))
)

# Average duration using histogram_avg (Azure Monitor enhancement)
histogram_avg(rate({"http.server.request.duration"}[5m]))

# Ensure you have the correct temporality:
# - Use rate() for cumulative histograms
# - Use raw values for delta histograms

指数直方图

指数直方图提供自动存储桶大小调整,不使用 'le' 标签:

# Native histogram queries (Prometheus 3.0+) - no 'le' needed
histogram_quantile(0.99,
  sum by ("service.name") (rate({"http.server.request.duration"}[2m]))
)

# 95th percentile without grouping dimensions
histogram_quantile(0.95,
  rate({"http.server.duration"}[5m])
)

# Calculate fraction of requests under 200ms
histogram_fraction(0, 0.2, rate({"http.server.request.duration"}[1h]))

资源属性处理

OpenTelemetry 资源属性将成为可筛选的 PromQL 标签:

# Service identification
{__name__="http.server.duration", "service.name"="frontend"}

# Environment separation
{__name__="http.server.duration", "deployment.environment"="production"}

# Grouping on unique cloud resources
Count by ("Microsoft.resourceid") ({"http.server.duration"})

注释

不建议对保留的 "__name__" 标签使用正则表达式筛选,以获得最佳查询性能。 避免 {__name__=~“http.*”} 等模式。

查询优化提示

限制高基数指标的时间范围

# Be cautious with broad queries over long time ranges
sum by ("service.name") ({"http.server.duration"}[1h])

尽可能提前聚合

# Better - aggregate before complex operations
sum(rate({"http.server.request.count"}[5m])) by ("service.name")

# Avoid - complex operations on high cardinality labels unless necessary
rate(sum({"http.server.request.count"}[5m]) by ("service.name", "http.method", "http.status_code"))

有关聚合运算符的详细信息,请参阅 Prometheus 聚合运算符

排查常见问题

名称中带点的指标缺失

问题:查询不返回指标的数据,例如 http.server.duration

解决方案:使用大括号或 __name__ 选择器进行 UTF-8 引用:

# Try UTF-8 quoting with curly braces first
{"http.server.duration"}

# Fallback to __name__
{__name__="http.server.duration"}

错误的比率计算

问题:速率计算显示意外的峰值或下降。

解决方案:验证时态并调整查询:

# For cumulative metrics
rate({"http.server.request.count"}[5m])

# For delta metrics (no rate needed)
{"http.server.request.count"}

标签名称冲突

问题:OpenTelemetry 资源属性与 Prometheus 约定冲突。

解决方案:使用显式标签选择:

# Specify the exact label name
{"service.name"="my-service"}

# Avoid regex when possible
{"service.name"!~"other-service"}