首页
/ Prometheus 联邦机制详解:/federate 端点、分层监控架构与 honor_labels 配置

Prometheus 联邦机制详解:/federate 端点、分层监控架构与 honor_labels 配置

2026-09-03 16:07:03作者:晏闻田Solitary

本文以仓库中 federation 文档 为主体,完整讲解 Prometheus 联邦(Federation)机制:它支持的两种典型使用场景(分层联邦与跨服务联邦)、/federate 端点的 match[] 参数语义,以及如何通过 scrape_configs 将一台 Prometheus 的指标联邦到另一台。同时结合 web/federate.goweb/web.goscrape/scrape.go 的源码,深入剖析联邦端点的数据选择、外部标签附加、原生直方图处理等底层实现,读完你可以独立完成一套可运行的联邦拓扑配置,并理解其边界与陷阱。

什么是联邦

联邦允许一台 Prometheus 服务器从另一台 Prometheus 服务器抓取(scrape)选定的时间序列。其本质是:源 Prometheus 暴露一个特殊的 /federate 端点,把指定序列的最新样本以指标暴露格式输出;目标 Prometheus 则像抓取普通目标一样,把这个端点当作抓取目标。

需要注意的官方说明是:原生直方图(native histograms)的联邦要求抓取侧在 scrape 配置中设置 scrape_native_histograms: true,这意味着抓取将使用 protobuf 格式。若同一指标名下混合了多种样本类型(float、计数器直方图、量规直方图),联邦负载中会出现多个同名但类型不同的 MetricFamily(float 样本在联邦中始终按 untyped 处理,而直方图样本保留完整类型信息)。这在技术上违反了 protobuf 暴露格式的规则,但 Prometheus 仍能正确摄取全部指标——这一点在 federation 文档 开头即有明确警示,源码中亦可见对应的实现(见下文“原生直方图的联邦”一节)。

联邦的使用场景

文档指出联邦有两类常见用途:构建可扩展的分层监控体系,或把一个服务的关联指标拉入另一个服务的 Prometheus。

分层联邦(Hierarchical Federation)

分层联邦使 Prometheus 能够扩展到拥有数十个数据中心、数百万节点的环境。其拓扑呈树形:上层 Prometheus 从大量下层 Prometheus 收集聚合后的时间序列。

典型配置是:大量按数据中心部署的 Prometheus 服务器负责高细节度的数据采集(instance 级下钻),再配一组全局 Prometheus 服务器,只从这些本地服务器收集聚合数据(job 级下钻)。由此形成“全局聚合视图 + 本地详细视图”的组合。

这一模式的实践含义是:下钻到实例级别的细节只在本地层可见,全局层存储的是聚合序列(通常来自 job: 前缀的 recording rules 或 job="prometheus" 之类的固定 label 选择器)。

跨服务联邦(Cross-service Federation)

跨服务联邦中,某个服务的 Prometheus 被配置为从另一个服务的 Prometheus 抓取选定数据,从而在单台服务器上对两个数据集同时进行告警与查询。

文档给出的例子是:集群调度器会暴露其上各服务实例的资源使用情况(内存、CPU),而运行在集群上的服务只暴露应用级指标。这两组指标往往由相互独立的 Prometheus 抓取。借助联邦,承载服务级指标的 Prometheus 可以从集群 Prometheus 拉取本服务的集群资源使用指标,使两组指标在同一台服务器内联合使用(例如关联告警、单面板展示)。

/federate 端点与 match[] 参数

在任意一台 Prometheus 上,/federate 端点可以获取该服务器上选定时间序列集合的当前值。使用约束与语义如下:

  • 必须至少指定一个 match[] URL 参数,否则请求被拒绝(400);
  • 每个 match[] 参数需指定一个瞬时向量选择器(instant vector selector),例如 up{job="api-server"}
  • 提供多个 match[] 参数时,选择的是所有匹配序列的并集

源码级实现剖析

/federate 路由在 web/web.go 注册,且经过 readyf 就绪检查与 CompressionHandler 压缩包装:

router.Get("/federate", readyf(httputil.CompressionHandler{
    Handler: http.HandlerFunc(h.federation),
}.ServeHTTP))

核心处理函数 federation() 位于 web/federate.go,其数据流程可以概括为五步:

1. 解析选择器。 端点通过 ParseMetricSelectors(req.Form["match[]"]) 解析全部 match[] 表单值,得到若干选择器组;解析失败直接返回 400

2. 时间窗口:lookback delta。 查询窗口固定为 [now - lookbackDelta, now]

mint = timestamp.FromTime(h.now().Time().Add(-h.lookbackDelta))
maxt = timestamp.FromTime(h.now().Time())

即每个序列只取 lookback 窗口内的最新一个样本lookbackDelta 默认 5 分钟,可由命令行参数 --web.lookback-delta 调整(见 cmd/prometheus/main.goDefault("5m").SetValue(&cfg.lookbackDelta))。

3. 选择与合并。 对每个选择器组调用 q.Select(ctx, true, hints, mset...),再用 storage.NewMergeSeriesSet(sets, 0, storage.ChainedSeriesMerge) 合并成单一序列集,并以 storage.NewBuffer 缓冲迭代器(缓冲区大小即 lookback 的微秒数)逐个取最新样本;取不到新样本时通过 PeekBack(1) 回退一个样本。

4. 丢弃 stale 标记。 由于暴露格式不支持 stale marker,值为 stale NaN 的样本会被直接丢弃:

if value.IsStaleNaN(f) || (fh != nil && value.IsStaleNaN(fh.Sum)) {
    continue
}

源码注释说明这对联邦的典型用途(联邦聚合序列)是足够的,陈旧性处理交由基于时间间隔的 staleness 机制完成。

5. 附加外部标签并分组输出。 端点从 GlobalConfig.ExternalLabels 取出全局外部标签,并确保其中包含 instance 键(若不存在则置为空串)。对每个序列,只有当该标签名未出现在序列已有标签中时才附加对应外部标签("Attach global labels if they do not exist yet",见 web/federate.go)。此外序列按指标名排序,保证输出确定性。

端点还暴露两个可观测性计数器,可在源 Prometheus 的 /metrics 中观测联邦服务质量:

  • prometheus_web_federation_errors_total —— 发送联邦响应期间发生的错误总数;
  • prometheus_web_federation_warnings_total —— 警告总数。

配置联邦:从源服务器抓取到 /federate

文档给出的核心操作步骤是:在目标 Prometheus 上,把源 Prometheus 的 /federate 端点配置为抓取目标,同时启用 honor_labels(避免覆盖源服务器暴露的标签),并传入所需的 match[] 参数。

下面是文档中的完整示例,它将 source-prometheus-{1,2,3}:9090 上所有 job="prometheus" 的序列、以及所有指标名以 job: 开头的序列,联邦到抓取方 Prometheus:

scrape_configs:
  - job_name: 'federate'
    scrape_interval: 15s

    honor_labels: true
    metrics_path: '/federate'

    params:
      'match[]':
        - '{job="prometheus"}'
        - '{__name__=~"job:.*"}'

    static_configs:
      - targets:
        - 'source-prometheus-1:9090'
        - 'source-prometheus-2:9090'
        - 'source-prometheus-3:9090'

各配置项的作用:

配置项 作用
metrics_path: '/federate' 将抓取路径指向联邦端点而非默认的 /metrics
params.match[] 附加到抓取 URL 的查询参数;多个值即文档所述“并集”语义
honor_labels: true 让目标侧标签(如 jobinstance)不覆盖序列中已暴露的标签
scrape_interval: 15s 联邦数据的更新周期,决定了上层看到的序列“新鲜度”上限

honor_labels 为什么必不可少

联邦场景下,源端点输出的每个样本自带完整标签集(包括源端的 instancejob 等)。若不设置 honor_labels,抓取侧会用目标自身的标签覆盖序列上的同名标签——所有序列的 instance 会被统一改成源 Prometheus 的地址(如 source-prometheus-1:9090),来自不同下层的同名序列就会互相混淆。

honor_labels 的语义在 scrape/scrape.gomutateSampleLabels 中实现:

if honor {
    target.LabelsRange(func(l labels.Label) {
        if !lset.Has(l.Name) {   // 样本标签已存在时,保留暴露值
            lb.Set(l.Name, l.Value)
        }
    })
} else {
    // 目标标签覆盖样本标签;
    // 冲突的被暴露标签会被重命名为 exported_<name>
    ...
    resolveConflictingExposedLabels(lb, conflictingExposedLabels)
}
  • honor_labels: truehonor == true 分支):仅当样本标签中不存在该目标标签时才写入,暴露的标签值被完整保留;
  • honor_labels: false:目标标签无条件覆盖样本标签,冲突的原暴露标签被加 exported_ 前缀重命名,以免信息丢失。

抓取循环在 scrape/scrape.go 处将该配置接入样本改写链(mutateSampleLabels(l, opts.target, opts.sp.config.HonorLabels, ...)),并随后执行 metric_relabel_configs。相关行为有专门测试覆盖,例如 scrape/scrape_test.go 中的 TestScrapeLoopAppend_HonorLabels(覆盖 HonorLabels=false/trueexported 前缀已存在、空标签值等情形)。

原生直方图的联邦

文档特别强调了原生直方图(native histograms)的联邦约束,源码给出了精确对应的实现细节(web/federate.go):

  • 仅 protobuf 格式可输出原生直方图。 若样本是非自定义桶的原生直方图,而响应协商出的格式不是 protobuf 系列(TypeProtoDelim / TypeProtoText / TypeProtoCompact),该样本会被跳过(源码注释:“Can't serve a native histogram with a non-protobuf format”)。这就是文档要求抓取侧开启 scrape_native_histograms: true 的原因——它使抓取走 protobuf 格式。
  • float 一律按 untyped 联邦。 输出分组时,float 样本统一装入 dto.Untyped
  • 直方图保留完整类型。 依据 CounterResetHint 区分输出 MetricType_GAUGE_HISTOGRAMMetricType_HISTOGRAM;当同一指标名同时出现 float 与直方图、或计数器与量规直方图时,端点会拆成多个同名 MetricFamily——源码注释明确承认“This would technically be an invalid exposition… we allow it and bend the rules to make federation possible”;
  • NHCB(schema -53 自定义桶)转经典直方图。 UsesCustomBuckets() 的直方图经 makeClassicHistogram 转换为经典 dto.Histogram 输出(桶边界取自 CustomValues,计数为累积值,+Inf 桶按 protobuf 规则省略),因此 NHCB 可以用非 protobuf 格式联邦。

配置侧,scrape_native_histograms 选项在 config/config.go 定义(ScrapeNativeHistograms *bool),全局默认值为 falseconfig/config.goDefaultGlobalConfig 注明“ScrapeNativeHistograms default changes to true”——即默认值变更在演进中),支持 global 与 per-scrape-config 两级覆盖(ScrapeNativeHistogramsEnabled() 判断逻辑见 config/config.go)。

联邦行为的边界与验证

结合源码与测试,使用 /federate 时值得记住的几条边界:

  1. 只输出最新值:每个序列仅返回 lookback 窗口内最新样本,/federate 是“当前值”快照接口,不是完整历史导出;
  2. 必须带 match[]web/federate_test.go 中,params: ""、空匹配、非法指标名等场景分别期望 400400 或空响应,验证了“至少一个 match[]”与选择器解析的行为;
  3. match[] 取并集:测试用例 match[]=test_metric1&match[]=test_metric2 验证了两个选择器返回合并序列;
  4. stale 样本不输出:测试数据 test_metric_stale 1+10x99 stale 用于验证 stale 值被丢弃;
  5. TSDB 未就绪时返回 503TestFederation_NotReadyweb/federate_test.go)以 tsdb.ErrNotReady 包装存储,期望 503 Service Unavailable——这解释了为什么 /federate 路由注册时包了 readyf
  6. 外部标签附加规则:全局 external_labels 只在序列未携带同名标签时附加,且 instance 键必然出现(缺失时为空串),这保证了即使源端未设置 instance,上层也能拿到一个确定的实例维度。

小结

联邦是 Prometheus 实现水平扩展与跨域指标汇聚的内置机制,而非外挂组件:

  • 拓扑上:分层联邦以“本地高细节 + 全局聚合”的树形结构支撑大规模部署;跨服务联邦让单台 Prometheus 能同时查询两个数据域;
  • 配置上:只需在目标侧的 scrape_configs 中把 metrics_path 指向 /federate、用 params.match[] 表达并集选择器、开启 honor_labels 保留源端标签;
  • 实现上/federate 端点(web/federate.go)在 lookback 窗口内取每个序列最新样本、丢弃 stale、按指标名分组并附加全局外部标签输出;float 以 untyped、直方图以完整类型输出,原生直方图要求 protobuf 抓取格式(scrape_native_histograms: true)。

在规划联邦拓扑时,应优先把聚合交给 recording rules(如 job: 前缀序列)完成,让上层只承担聚合序列的存储压力;/federate 端点配合 --web.lookback-delta 与抓取间隔共同决定了上层视图的时间分辨率与新鲜度。

登录后查看全文
热门项目推荐
相关项目推荐