Kubernetes 1.37 默认启用原生直方图:更准的延迟分位数,更少的时序

2026-09-12 23 预计阅读时间: 1 分钟
来源: kubernetes.io AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:9 分钟

Kubernetes v1.37 将原生直方图(Native Histograms)提升到 Beta,并默认启用。这个变化直接影响 API Server 延迟、调度耗时、容器运行时操作等指标:Prometheus 可以用更少的时序覆盖更宽的数值范围,同时更准确地计算 P95、P99 等分位数。

升级 Kubernetes 并不等于监控系统已经完成迁移。Kubernetes 负责暴露经典直方图和原生直方图,Prometheus 是否采集、Grafana 与告警规则使用哪一种格式,仍需要运维团队明确配置。

经典直方图的三个结构性问题

经典 Prometheus 直方图要求指标作者预先定义累积桶边界,例如:

0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10

这种模型容易遇到三个问题。

固定桶无法适应分布变化。 如果请求耗时从毫秒下降到微秒级,或者长尾延迟超过最大桶,已有边界就无法提供足够的分辨率。开发者必须在真正观察到分布之前猜测合适的桶。

每个桶都会增加时序。 经典格式把每个边界暴露为一条带有 le 标签的 _bucket 时序。指标原本已有的 verbresourcecode 等标签会与所有桶组合,放大 Prometheus 内存、抓取和 TSDB 存储成本。

分位数依赖桶内插值。 histogram_quantile() 只能根据固定边界估算桶内分布。桶跨度越大,估算误差越明显。

原生直方图改用动态指数桶,并把正值跨度、负值跨度、零值阈值和缩放参数编码在一条结构化时序中。Kubernetes 的默认配置包括:

  • BucketFactor: 1.1:相邻桶宽度最多增加 10%,默认配置下分位数的最坏相对误差约为 5%。
  • MaxBucketNumber: 160:限制单个直方图的桶数量,避免极端离群值持续扩大组件内存占用。
  • 单条结构化时序取代大量 _bucket{le="..."} 时序,直方图相关时序数量最多可减少约 90%。

Kubernetes 如何保持兼容

原生直方图能力集成在共享指标库 k8s.io/component-base/metrics 中,因此 kube-apiserver、kube-scheduler、kubelet、kube-controller-manager 和 kube-proxy 等组件都会继承支持。典型指标包括 apiserver_request_duration_secondsscheduler_plugin_execution_duration_secondsscheduler_scheduling_algorithm_duration_seconds

Beta 阶段的关键设计是双重暴露:

  • 经典桶继续存在,旧版仪表盘和基于 _bucket 的告警不需要立即修改。
  • 原生跨度通过 Prometheus Protobuf 负载同时暴露,支持原生直方图的采集器可以读取它们。
  • 普通文本或 OpenMetrics 文本抓取只能传输经典桶;Prometheus 启用原生直方图抓取后,会与 Kubernetes 指标端点协商 Protobuf 格式。

因此,Kubernetes v1.37 默认启用功能门控,只表示组件已经具备双重暴露能力,并不表示 Prometheus 会自动保存原生样本。

可以这样完成采集与查询迁移

下面假设使用 Prometheus 3.x。把配置加入对应的 scrape_configs,并根据现有环境补充服务发现、TLS 和鉴权设置:

scrape_configs:
  - job_name: kubernetes-apiservers
    scrape_native_histograms: true
    always_scrape_classic_histograms: true
    kubernetes_sd_configs:
      - role: endpoints

迁移期不要省略 always_scrape_classic_histograms: true。否则 Prometheus 可能只摄取原生格式,旧查询依赖的 _bucket_count_sum 时序会消失,现有面板和告警可能立即失效。

Prometheus 2.40 至 2.x 使用全局功能开关启动:

prometheus \
  --config.file=/etc/prometheus/prometheus.yml \
  --enable-feature=native-histograms

这个开关会影响所有抓取目标。Prometheus 3.x 更适合按 job 配置;较新版本中,全局原生直方图功能标志已经走向弃用。

采集完成后,可以并行运行经典查询和原生查询,比较结果:

# 经典格式:保留 le 维度后再计算跨实例 P99
histogram_quantile(
  0.99,
  sum by (le) (
    rate(apiserver_request_duration_seconds_bucket[5m])
  )
)
# 原生格式:直接聚合直方图样本,不再需要 le
histogram_quantile(
  0.99,
  sum(
    rate(apiserver_request_duration_seconds[5m])
  )
)

经典的 _count_sum 查询也应迁移为直方图函数。例如,可以这样计算平均请求耗时:

sum(rate(histogram_sum(apiserver_request_duration_seconds[5m])))
/
sum(rate(histogram_count(apiserver_request_duration_seconds[5m])))

实际改造时,需要保留查询所需的业务维度。例如按 verb 观察 API 请求时,应在原生查询中使用 sum by (verb),不能为了删除 le 而把所有有意义的标签一起聚合掉。

在测试环境中,还可以直接确认 Kubernetes 指标端点是否返回 Protobuf 双重暴露数据。下面的命令假设在具有 ServiceAccount 令牌且能够访问本机 API Server 的 Pod 内运行;--insecure 会跳过证书校验,只适合隔离的测试场景:

TOKEN="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)"

curl --insecure \
  -H 'Accept: application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=delimited' \
  -H "Authorization: Bearer ${TOKEN}" \
  https://localhost:6443/metrics \
  --output metrics.pb

ls -lh metrics.pb

响应是二进制 Protobuf,不能用普通文本搜索验证。解码后,直方图 MetricFamily 应同时包含传统 bucket 数据,以及 schemapositive_span 等原生字段。

上线顺序与回滚边界

稳妥的迁移可以分成四步:开启两种格式采集;逐个迁移 Grafana 面板和告警;在预发布及生产环境对比分位数、SLO 和告警行为;确认旧查询全部退出后,再设置 always_scrape_classic_histograms: false。最后一步才会释放经典桶产生的大量时序和存储开销。

上线前建议检查:

  • Prometheus 版本是否支持目标配置项和原生直方图查询。
  • 远程写入、长期存储和查询前端是否都能处理原生直方图,而不只是本地 Prometheus。
  • recording rules、Grafana 变量、SLO 工具和告警规则中是否仍引用 _bucket_count_sum
  • 新旧查询是否使用相同的标签聚合维度和时间窗口。
  • Prometheus 内存、抓取负载、WAL、远程写入流量和 TSDB 占用是否符合预期。

如果采集侧出现兼容性问题,将对应 job 的 scrape_native_histograms 设置为 false 即可停止摄取原生格式,不需要重启 Kubernetes。更彻底的组件侧回滚可以使用 --feature-gates=NativeHistograms=false,但这需要重启相关 Kubernetes 组件。

原生直方图进入 Beta 并默认启用,不代表经典桶应在升级当天被删除。合理做法是把 Kubernetes v1.37 当作迁移起点:先双写、再改查询、验证完整链路,最后关闭经典格式采集。这样既能获得更稳定的分位数精度和显著的时序节省,也能保留清晰、快速的回滚路径。


相关推荐