影评周公子 2026-04-04 06:05 采纳率: 98.9%
浏览 0
已采纳

Prometheus 查询中如何用 label_values 包含特定字段?

在 Prometheus 的 `label_values()` 函数使用中,一个常见问题是:**如何仅获取包含特定字符串(如 `"prod"` 或 `"api_"`)的 label 值?** `label_values()` 本身不支持正则匹配或子串过滤,它仅返回某 metric 下指定 label 的所有原始取值(如 `label_values(http_requests_total, job)` 返回所有 `job` 值)。若想筛选含特定字段的值(例如只取 `job` 中以 `"api-"` 开头的实例),直接调用 `label_values()` 无法实现。用户常误以为可结合 Rego、PromQL 过滤或外部工具(如 Grafana 变量查询)一并完成,结果导致变量为空或漏配。正确解法需分层处理:先通过 `count by (label_name)` + `regex` 匹配的 PromQL 查询预筛数据(如 `count by (job) (http_requests_total{job=~"api-.*"})`),再配合 Grafana 的「Custom」或「Query」类型变量 + API 代理/Recording Rule 预计算,或借助 Prometheus API + 外部脚本做后处理。忽略该限制易引发监控面板下拉选项缺失、告警配置失效等生产问题。
  • 写回答

1条回答 默认 最新

  • Airbnb爱彼迎 2026-04-04 06:05
    关注
    ```html

    一、现象层:为什么 label_values() 无法直接做子串过滤?

    在 Grafana 变量配置中,label_values(http_requests_total, job) 会返回所有 job label 的原始值(如 "api-auth", "prod-db", "ci-runner"),但它不接受任何 PromQL 过滤器或正则表达式参数。其底层调用的是 Prometheus 的 /api/v1/labels/api/v1/label/<name>/values 端点,仅提供“全量枚举”,无服务端计算能力。这是设计使然——Prometheus 标签值索引是倒排的,但不支持模糊匹配查询。

    二、机理层:Prometheus 标签系统的存储与查询边界

    • 标签值存储:基于 LSM-Tree 的 chunk 存储 + 内存中的 label index,仅支持精确匹配(=)、前缀匹配(=~ "prefix.*")和集合匹配(=~ "a|b|c"
    • API 层限制/api/v1/label/<name>/values 不支持 match[] 参数,而 /api/v1/series 虽支持 match[],但返回的是时间序列元数据(含完整 label set),需客户端解析
    • PromQL 表达式语义count by (job) 是聚合操作,可结合 {job=~"api_.*"} 实现逻辑筛选,但该结果仍是指标向量,非纯字符串列表

    三、实践层:四种生产级可行方案对比

    方案适用场景延迟/维护成本Grafana 变量类型是否需额外组件
    ✅ Recording Rule + label_values()高频访问、稳定 label 模式(如 job=~"prod.*"低(每 scrape interval 计算一次)Query
    ✅ Prometheus API + Grafana Query 变量动态性强、需实时响应(如按命名空间筛选 pod)中(每次变量刷新触发 HTTP 请求)Query否(仅需 Grafana 7.2+)
    ⚠️ 外部脚本代理(如 Python FastAPI)复杂逻辑(多 label 关联、白名单校验、缓存策略)高(需部署、监控、TLS 配置)Custom / API

    四、架构层:推荐的分层处理流程图

    flowchart LR
      A[用户在 Grafana 选择变量] --> B{Grafana 变量类型}
      B -->|Query 类型| C[向 Prometheus /api/v1/series 发起 match[] 查询]
      B -->|Custom 类型| D[调用预置静态列表或外部 API]
      C --> E[解析响应中的 target label 值]
      E --> F[去重 & 排序]
      F --> G[渲染下拉菜单]
      D --> G
      C -.-> H[建议添加 caching: 30s]
      E -.-> I[避免返回 >500 条导致 UI 卡顿]
    

    五、代码层:可即用的 PromQL + Grafana 配置示例

    Recording Rule(写入 prometheus.yml):

    groups:
    - name: filtered_job_labels
      rules:
      - record: job:filtered_api_prod
        expr: count by (job) (http_requests_total{job=~"api_.*|prod.*"})
    

    Grafana Query 变量(Type=Query):

    label_values(job:filtered_api_prod, job)
    

    或直连 API(Grafana 9+ 支持):

    https://prometheus.example.com/api/v1/series?match[]={job=~"api_.*|prod.*"}&start=now-1h
    

    (注意:需在 Grafana 数据源中启用 “Direct” 访问模式,并配置 CORS)

    六、陷阱层:五个高频误用及后果

    1. label_values() 中错误拼接 PromQL:label_values(count by (job)(...), job) → 语法错误,Grafana 报 invalid parameter "query"
    2. 使用 regex 函数于 PromQL 表达式中再套 label_values()regex 是客户端函数,Prometheus 不识别
    3. 忽略 label cardinality:当 job=~"prod.*" 匹配到 2000+ 值时,Grafana 渲染卡顿甚至 OOM
    4. 未设置变量 refresh on time range change → 时间范围切换后仍显示旧 label,造成误判
    5. label_values(up{job=~"api.*"}, instance) 用于告警规则模板 → 告警引擎不支持动态 label 查询,导致 template execution error

    七、演进层:未来可观测性栈的替代路径

    随着 OpenTelemetry Collector 和 Cortex/Mimir 的普及,更健壮的方案正在浮现:

    • OTel Attribute Filtering:在采集侧通过 attributes_processor 提前注入 env_type="prod" 等语义化 label,降低查询复杂度
    • Mimir Label Indexing Extensions:Mimir v1.12+ 支持 /api/v1/label_values?match[]=...,已突破原生 Prometheus 限制
    • Grafana 10+ 的 Unified Alerting + Labels API:允许在 alert rule 中引用 labels_from_query,实现告警维度与面板变量同源
    ```
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 已采纳回答 4月5日
  • 创建了问题 4月4日