Prometheus 联邦机制详解:/federate 端点、分层监控架构与 honor_labels 配置
本文以仓库中 federation 文档 为主体,完整讲解 Prometheus 联邦(Federation)机制:它支持的两种典型使用场景(分层联邦与跨服务联邦)、/federate 端点的 match[] 参数语义,以及如何通过 scrape_configs 将一台 Prometheus 的指标联邦到另一台。同时结合 web/federate.go、web/web.go 与 scrape/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.go 中 Default("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 |
让目标侧标签(如 job、instance)不覆盖序列中已暴露的标签 |
scrape_interval: 15s |
联邦数据的更新周期,决定了上层看到的序列“新鲜度”上限 |
honor_labels 为什么必不可少
联邦场景下,源端点输出的每个样本自带完整标签集(包括源端的 instance、job 等)。若不设置 honor_labels,抓取侧会用目标自身的标签覆盖序列上的同名标签——所有序列的 instance 会被统一改成源 Prometheus 的地址(如 source-prometheus-1:9090),来自不同下层的同名序列就会互相混淆。
honor_labels 的语义在 scrape/scrape.go 的 mutateSampleLabels 中实现:
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: true(honor == 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/true、exported 前缀已存在、空标签值等情形)。
原生直方图的联邦
文档特别强调了原生直方图(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_HISTOGRAM或MetricType_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),全局默认值为 false(config/config.go 中 DefaultGlobalConfig 注明“ScrapeNativeHistograms default changes to true”——即默认值变更在演进中),支持 global 与 per-scrape-config 两级覆盖(ScrapeNativeHistogramsEnabled() 判断逻辑见 config/config.go)。
联邦行为的边界与验证
结合源码与测试,使用 /federate 时值得记住的几条边界:
- 只输出最新值:每个序列仅返回 lookback 窗口内最新样本,
/federate是“当前值”快照接口,不是完整历史导出; - 必须带
match[]:web/federate_test.go 中,params: ""、空匹配、非法指标名等场景分别期望400、400或空响应,验证了“至少一个match[]”与选择器解析的行为; - 多
match[]取并集:测试用例match[]=test_metric1&match[]=test_metric2验证了两个选择器返回合并序列; - stale 样本不输出:测试数据
test_metric_stale 1+10x99 stale用于验证 stale 值被丢弃; - TSDB 未就绪时返回 503:
TestFederation_NotReady(web/federate_test.go)以tsdb.ErrNotReady包装存储,期望503 Service Unavailable——这解释了为什么/federate路由注册时包了readyf; - 外部标签附加规则:全局
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 与抓取间隔共同决定了上层视图的时间分辨率与新鲜度。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00