Prometheus 3.0 迁移指南:破坏性变更全解与源码级迁移实践
本文围绕 Prometheus 3.0 的官方迁移指南(docs/migration.md)展开,系统梳理从 Prometheus 2.x 升级到 3.0 及更高版本时的全部破坏性变更,涵盖已移除的 feature flag、配置项改名与默认值变化、PromQL 语义调整、Scrape 协议收紧、TSDB 格式约束、UTF-8 命名支持、日志格式切换等关键主题,并结合当前仓库源码给出每一项变更的底层实现证据与可操作的迁移方案。读完本文,你可以独立完成一次 2.x → 3.x 的升级,并能解释每项变更在源码中的具体落点。
一、背景:为什么 Prometheus 3.0 是破坏性发布
按照 Prometheus 的稳定性承诺(docs/stability.md),3.0 版本引入了一批向后不兼容的变更。这些变更大多是把曾经隐藏在 feature flag 背后的实验特性"转正"为默认行为,同时清理了一批历史遗留的边界情况。对使用者而言,升级前需要逐项核对本文列出的变更点,尤其是涉及 PromQL 查询语义、Scrape 协议和 le/quantile 标签值的部分——它们会静默改变既有查询、告警和看板的结果。
二、Flags:被移除的 feature flag 与专属 CLI 参数
2.1 已转正并移除的 feature flag
以下 feature flag 在 3.0 中被移除,其能力已并入默认行为。继续在 --enable-feature 中传递它们只会收到警告:
promql-at-modifier:@ <timestamp>时间修饰符已默认支持;promql-negative-offset:负数偏移量已默认支持;new-service-discovery-manager:新服务发现管理器已成为默认实现;expand-external-labels:外部标签值中的环境变量引用${var}或$var现在会按当前环境变量的值展开,未定义的变量替换为空字符串,$$用于转义$字符;no-default-scrape-port:Prometheus v3 不再按 scheme 为抓取目标自动补端口。目标在标签中将原样呈现。如果你依赖https://example.com/metrics被表示为https://example.com/metrics:443、http://example.com/metrics被表示为http://example.com/metrics:80的旧行为,需要自行在目标 URL 中显式写上端口;agent:改为使用专属的--agentCLI flag(见下文);remote-write-receiver:改为使用专属的--web.enable-remote-write-receiverflag 来启用 remote write 接收端点;auto-gomemlimit:v3 会自动将GOMEMLIMIT设置为与 Linux 容器内存限制一致;没有容器限制或进程运行在容器外时,使用系统总内存。可通过--no-auto-gomemlimit关闭;auto-gomaxprocs:v3 会自动将GOMAXPROCS设置为与 Linux 容器 CPU 配额一致。可通过--no-auto-gomaxprocs关闭。
从源码可以确认这些变更的落点:
- 在 cmd/prometheus/main.go 中注册了专属的
--agentflag:a.Flag("agent", "Run Prometheus in 'Agent mode'.").BoolVar(&agentMode),而 agent 专属的存储参数(--storage.agent.path、--storage.agent.retention.min-time等)均通过agentOnlyFlag辅助函数注册(cmd/prometheus/main.go#L174-L180),并在 server 模式下校验冲突; - remote write 接收端点对应的 flag 定义在 cmd/prometheus/main.go#L478:
a.Flag("web.enable-remote-write-receiver", "Enable API endpoint accepting remote write requests."); auto-gomemlimit/auto-gomaxprocs现在以普通 CLI flag 形式存在,并附带--auto-gomemlimit.ratio、--auto-gomemlimit.refresh-interval等调参选项(cmd/prometheus/main.go#L435-L441),支持在运行时(如 Vertical Pod Autoscaler 场景)周期性地重新探测内存限制。
2.2 native-histograms 自 v3.9 起成为 no-op
从 v3.9 开始,feature flag native-histograms 不再有任何效果。原生直方图已成为稳定特性,但抓取它需要通过配置显式开启:在全局或每个 scrape job 中设置 scrape_native_histograms(该配置选项在 v3.8 引入)。
源码印证:--enable-feature=native-histograms 现在只会打出一条警告(cmd/prometheus/main.go#L266-L267):
case "native-histograms":
logger.Warn("This option for --enable-feature is a no-op. To scrape native histograms, set the scrape_native_histograms scrape config setting to true.", "option", o)
对应的配置字段分别定义在 config/config.go 的 GlobalConfig(ScrapeNativeHistograms *bool,对应 scrape_native_histograms)和 config/config.go#L809 的 ScrapeConfig 中。
三、Configuration:配置项改名与默认值变化
3.1 scrape_classic_histograms 改名为 always_scrape_classic_histograms
抓取 job 级配置项 scrape_classic_histograms 已改名为 always_scrape_classic_histograms。如果你使用 scrape_native_histograms 抓取原生直方图,同时又希望保留端点可能一并暴露的经典直方图,务必新增(或从旧名迁移)该配置,否则会丢失经典直方图数据。
源码中该字段以指针类型区分"未设置"与"显式设置",全局级在 config/config.go#L538(AlwaysScrapeClassicHistograms bool),scrape job 级在 config/config.go#L811(AlwaysScrapeClassicHistograms *bool),job 级配置可覆盖全局默认。仓库测试数据中也提供了多个相关示例,例如 config/testdata/local_enable_always_scrape_classic_hist.good.yml、config/testdata/global_convert_classic_hist_to_nhcb.good.yml,可用于核对新旧名称的写法差异。
3.2 remote_write 的 http_config.enable_http2 默认值改为 false
remote_write 配置中 http_config.enable_http2 的默认值由 true 变为 false。在 v2 中 remote write 的 HTTP 客户端默认使用 HTTP/2;但在 v3 中,为了让多个 remote write 队列能够并行地跑在多个 socket 上,默认不再使用 HTTP/2 更合适。如果你希望 remote write 继续走 HTTP/2,需要在 remote_write 配置段中显式设置:
remote_write:
- url: "http://ingest.example.com:4001/api/v1/write"
http_config:
enable_http2: true
四、PromQL:三个语义层面的行为变更
4.1 正则表达式中的 . 现在匹配换行符
PromQL 中正则表达式的 . 模式现在可以匹配换行符 \n。这同时作用于查询匹配器和 relabel 配置中的正则。以下组合在 v2 中不匹配,在 v3 中会匹配:
.*额外匹配foo\n与Foo\nBar;foo.?bar额外匹配foo\nbar;foo.+bar额外匹配foo\nbar。
如果你希望 v3 保持 v2 的行为,需要把所有 . 替换为 [^\n],例如将 foo.* 改写为 foo[^\n]*。
4.2 范围选择器与回看窗口左边界改为"开"
Range 选择器与 lookback 选择器由原来的"左闭右闭"变为左开右闭,行为更加一致。该变更只影响范围/回看窗口的左边界恰好与某个样本时间戳重合的查询。
一个直观的例子:假设某时间序列样本恰好以 1 分钟均匀间隔产生。在 v2 中,[5m] 范围查询通常返回 5 个样本,但如果查询评估时刻恰好与一次抓取对齐,会返回 6 个样本;v3 中这类查询在均匀间隔下总是返回 5 个样本。
该变更对子查询(subquery)影响尤为突出,因为子查询的评估时刻天然等距且对齐到子查询分辨率的整数倍,而查询前端又常把子查询对齐到 step 的整数倍——多重对齐叠加后极易形成用户无意的"完美对齐"。例如,在这样完全对齐的系统中,v2 里 foo[1m:1m] 可能一直返回两个点,足以做 rate 计算;而 v3 中同一子查询只返回一个点,无法进行 rate/increase 计算,结果是 No Data。
迁移方式是把窗口拉长,确保覆盖多于一个点。上例中 foo[2m:1m] 无论查询如何对齐都返回两个点。具体改写形式取决于预期结果,不存在普适的一键替换方案。测试同样容易受影响,修复方式是调整期望的样本数或扩大范围。
4.3 holt_winters 函数改名并被实验性 flag 守护
holt_winters 函数已改名为 double_exponential_smoothing,并且现在受 promql-experimental-functions feature flag 守护。要继续使用该函数,必须同时完成两件事:
- 将查询中的
holt_winters改写为double_exponential_smoothing; - 在启动命令行中传递
--enable-feature=promql-experimental-functions。
源码印证:cmd/prometheus/main.go#L261-L263 中该 flag 会设置 c.parserOpts.EnableExperimentalFunctions = true,将实验性函数开关传递给 PromQL 解析器。
五、Scrape 协议:Content-Type 校验收紧(破坏性变更)
Prometheus v3 对抓取时收到的 Content-Type 头更加严格:
- v2 的行为:目标未指定 Content-Type、或头无法解析/不被识别时,默认回退到标准 Prometheus 文本协议。这可能导致抓取数据被错误解析;
- v3 的行为:上述情况下直接判定抓取失败。
如果某个抓取目标无法提供正确的 Content-Type 头,可以使用 fallback_scrape_protocol 参数显式指定回退协议。该参数在源码中的字段为 config/config.go#L807 的 ScrapeFallbackProtocol ScrapeProtocol(YAML key fallback_scrape_protocol),其合法性校验在 config/config.go#L986 完成,支持的取值包括 OpenMetricsText0.0.1/1.0.0/2.0.0、PrometheusProto、PrometheusText0.0.4/1.0.0。仓库中的正/反示例可以直接参考:
- 正确用法:config/testdata/conf.good.yml 中的
fallback_scrape_protocol: PrometheusText0.0.4; - 错误用法:config/testdata/scrape_config_files_fallback_scrape_protocol1.bad.yml(非法协议名)与 config/testdata/scrape_config_files_fallback_scrape_protocol2.bad.yml(该参数不接受列表形式),两者在 config/config_test.go 中有对应的失败断言。
这是一个破坏性变更:过去在 v2 下可能"歪打正着"成功的抓取,在 v3 中若未指定回退协议将失败。请确保抓取端点返回以下受支持的 Content-Type 之一:
application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=delimitedtext/plain;version=0.0.4text/plain;version=1.0.0application/openmetrics-text;version=0.0.1application/openmetrics-text;version=1.0.0
六、Miscellaneous:存储、命名、日志与通知的其余变更
6.1 TSDB 格式与降级限制
TSDB 格式在 v2.55 中已为索引格式变更做了微调。由此带来一条硬约束:v3 的 TSDB 只能被 v2.55 或更新版本读取。升级到 v3 后,你最多只能降级回 v2.55,再低就会丢失 TSDB 持久化数据。官方给出的额外保险措施是:先升级到 v2.55、确认运行正常后,再升级到 v3。
6.2 TSDB 兼容存储的查询契约
TSDB 兼容的存储现在必须返回与指定选择器相匹配的查询结果。这主要影响第三方实现,尤其是实现了 remote_read 的服务。该契约不会被显式强制执行,违反它可能导致未定义行为。
6.3 UTF-8 指标名与标签名
v3 支持在指标名和标签名中使用 UTF-8。这意味着升级后,指标和标签名可能随端点实际暴露的内容发生变化;此前会被判为非法的名称现在将合法通过。如果希望保留旧版校验行为,可在配置中指定 legacy 校验方案:
全局配置:
global:
metric_name_validation_scheme: legacy
或按 scrape job 粒度配置:
scrape_configs:
- job_name: job1
metric_name_validation_scheme: utf8
- job_name: job2
metric_name_validation_scheme: legacy
仓库中的 config/testdata/metric_name_validation_scheme.bad.yml 展示了该字段对非法取值的校验。
6.4 日志消息格式:从 go-kit/log 切换到 log/slog
v3 的日志底层从 go-kit/log 迁移到了标准库 log/slog(仓库中对应 util/logging 模块),日志字段名与格式随之变化。旧格式示例:
ts=2024-10-23T22:01:06.074Z caller=main.go:627 level=info msg="No time or size retention was set so using the default time retention" duration=15d
ts=2024-10-23T22:01:06.074Z caller=main.go:671 level=info msg="Starting Prometheus Server" mode=server version="(version=, branch=, revision=91d80252c3e528728b0f88d254dd720f6be07cb8-modified)"
ts=2024-10-23T22:01:06.074Z caller=main.go:676 level=info build_context="(go=go1.23.0, platform=linux/amd64, user=, date=, tags=unknown)"
ts=2024-10-23T22:01:06.074Z caller=main.go:677 level=info host_details="(Linux 5.15.0-124-generic #134-Ubuntu SMP Fri Sep 27 20:20:17 UTC 2024 x86_64 gigafips (none))"
新格式对应输出:
time=2024-10-24T00:03:07.542+02:00 level=INFO source=/home/user/go/src/github.com/prometheus/prometheus/cmd/prometheus/main.go:640 msg="No time or size retention was set so using the default time retention" duration=15d
time=2024-10-24T00:03:07.542+02:00 level=INFO source=/home/user/go/src/github.com/prometheus/prometheus/cmd/prometheus/main.go:681 msg="Starting Prometheus Server" mode=server version="(version=, branch=, revision=7c7116fea8343795cae6da42960cacd0207a2af8)"
time=2024-10-24T00:03:07.542+02:00 level=INFO source=/home/user/go/src/github.com/prometheus/prometheus/cmd/prometheus/main.go:686 msg="operational information" build_context="(go=go1.23.0, platform=linux/amd64, user=, date=, tags=unknown)" host_details="(Linux 5.15.0-124-generic #134-Ubuntu SMP Fri Sep 27 20:20:17 UTC 2024 x86_64 gigafips (none))" fd_limits="(soft=1048576, hard=1048576)" vm_limits="(soft=unlimited, hard=unlimited)"
要点:ts 变为 time、caller 变为 source、level=info 变为 level=INFO。如果你有基于日志字段的采集管道或告警规则,需要同步更新解析逻辑。
6.5 le 与 quantile 标签值在摄入时归一化
v3 中,经典直方图 le 标签和 summary quantile 标签的值在摄入时统一归一化。v2 中这些标签的取值在某些情况下依赖抓取协议(protobuf 与文本格式不一致),例如端点暴露的 my_classic_hist{le="1"} 经文本格式摄入为 my_classic_hist{le="1"},经 protobuf 摄入却变成 my_classic_hist{le="1.0"}——这改变了指标的身份,给查询带来困扰。v3 中无论哪种协议,最终一律归一化为浮点表示,即总是摄入 my_classic_hist{le="1.0"}。
直接后果:任何把 le、quantile 值写为整数的告警、记录规则与看板(如 le="1")在升级后将停止工作。
官方给出的两种应对方式:
- 推荐方案:修正所有对整数形式
le、quantile值的引用,接受跨越升级时刻的某些查询结果可能不准确; - 备选方案:在抓取目标时使用
metric_relabel_configs还原旧标签。仅对确实产生这类标签的指标应用:
metric_relabel_configs:
- source_labels:
- quantile
target_label: quantile
regex: (\d+)\.0+
- source_labels:
- le
- __name__
target_label: le
regex: (\d+)\.0+;.*_bucket
6.6 禁止通过 v1 API 配置 Alertmanager
Prometheus 3 不再支持 Alertmanager 的 v1 API,事实上要求 Alertmanager 0.16.0 或更新版本。仍在使用旧版本或 alerting: alertmanagers: [api_version: v1] 配置的用户,需要升级 Alertmanager 并将配置改为 api_version: v2。
七、Agent 模式:从 feature flag 到专属 flag
在 2.x 中,Agent 模式通过 --enable-feature=agent 开启;v3 起必须改用专属的 --agent CLI flag。Agent 模式将 Prometheus 变成一个只负责本地抓取与 remote write 的轻量代理:它不保留长期查询存储(依赖 WAL),也不做本地 PromQL 查询,数据通过 remote write 送往全局层(如 Prometheus、Cortex、Thanos 等),架构示意如下:
源码中,--agent flag 在 cmd/prometheus/main.go#L658 注册;开启 agent 模式后,一批 --storage.agent.* 参数生效(如 WAL 路径、保留时长、WAL 压缩等,见 cmd/prometheus/main.go#L556-L596),同时 server 专属 flag 会被校验拒绝(cmd/prometheus/main.go#L712),保证两种模式不混用。更详细的模式说明见 docs/prometheus_agent.md。
八、迁移清单与降级策略速查
| 变更点 | 影响 | 迁移动作 |
|---|---|---|
| 9 个 feature flag 移除 | --enable-feature 中出现被警告的项 |
清理命令行;agent/remote-write-receiver 改用专属 flag |
native-histograms no-op(v3.9+) |
原生直方图抓取行为 | 改设 scrape_native_histograms 全局/job 配置 |
scrape_classic_histograms 改名 |
同时需要经典+原生直方图 | 改用 always_scrape_classic_histograms |
remote_write HTTP/2 默认关闭 |
写链路性能特征 | 需要时显式 http_config.enable_http2: true |
正则 . 匹配换行 |
匹配器/relabel 命中范围扩大 | 需要旧行为则改为 [^\n] |
| 范围/回看窗口左开右闭 | 完全对齐时样本数减少,子查询可能 No Data | 拉长窗口,如 foo[1m:1m] → foo[2m:1m] |
holt_winters 改名 |
实验性函数不可用 | 改名 + --enable-feature=promql-experimental-functions |
| Content-Type 严格校验 | 抓取直接失败 | 端点返回受支持头,或配置 fallback_scrape_protocol |
| TSDB 版本约束 | 无法降级到 v2.55 之前 | 先升 v2.55 验证,再升 v3 |
| UTF-8 名称 | 指标/标签名可能变化 | 需要旧校验则设 metric_name_validation_scheme: legacy |
| 日志格式切换 | 日志解析/采集管道 | 更新 ts/caller/level 等字段的解析 |
le/quantile 归一化 |
le="1" 类引用失效 |
修正为 le="1.0",必要时用 metric_relabel_configs |
| Alertmanager v1 API 移除 | 通知链路中断 | 升级 Alertmanager ≥ 0.16.0,配置改用 api_version: v2 |
最后需要说明适用前提:本指南以当前仓库版本(v3 系列,native-histograms 已为 no-op 的 v3.9+ 状态)为准,从 v2 的任意版本升级前,建议先按 docs/installation.md 核对运行环境要求,并优先采用"v2.55 中转验证"的稳妥路径。如果你还在 1.x 时代,Prometheus 2.0 的迁移请参考 2.55 版本的官方迁移文档,本文不再展开。
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 StartedRust0622
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
