
【集群】云原生批调度实战:Volcano 数据收集方法深度解析与Prometheus Histogram误差问题

本系列《云原生批调度实战:Volcano 监控与性能测试》计划分为以下几篇,点击查看其它内容。
- 云原生批调度实战:调度器测试与监控工具 kube-scheduling-perf
- 云原生批调度实战:调度器测试与监控工具 kube-scheduling-perf 实操注意事项说明
- 云原生批调度实战:调度器测试监控结果
- 云原生批调度实战:本地环境测试结果与视频对比分析
- 监控与测试环境解析:测试流程拆解篇
- 监控与测试环境解析:指标采集与可视化篇
- 监控与测试环境解析:自定义镜像性能回归测试
- 监控与测试环境解析:数据收集方法深度解析与Prometheus Histogram误差问题
- 云原生批调度实战:Volcano调度器enqueue功能禁用与性能测试
- 云原生批调度实战:Volcano Pod创建数量不足问题排查与Webhook超时修复
- 云原生批调度实战:Volcano版本修改与性能测试优化
- 云原生批调度实战:Volcano Webhook禁用与性能瓶颈分析
在前期的文章中,我提到了调度器性能对比分析中一个重要论断:传统方法使用Prometheus会造成很大误差,而audit-exporter方法能够准确记录性能。当时我误以为这种差异源于数据处理阶段的Prometheus histogram统计方法,但深入分析指标采集链路后发现,两种方法的核心差异实际上在数据收集阶段,而非数据处理阶段。
本文旨在澄清这一技术细节,并深入探讨Prometheus histogram的误差机制与替代方案。
🎯 问题澄清:数据收集 vs 数据处理
1. 传统Prometheus方法 vs Audit-Exporter方法
传统Prometheus方法的数据收集路径
传统的Kubernetes调度器性能监控依赖调度器自身暴露的Prometheus指标:
graph LR A[调度器内部逻辑] --> B[调度器暴露metrics端点] B --> C[Prometheus定期抓取] C --> D[存储到TSDB] D --> E[Grafana查询展示]
核心特点:
- 数据源:调度器进程内部的instrumentation代码
- 时间精度:受限于调度器代码的埋点位置和精度
- 数据完整性:可能遗漏调度过程中的某些阶段
- 系统开销:对调度器性能有直接影响
Audit-Exporter方法的数据收集路径
而audit-exporter方法从kube-apiserver的审计日志中提取性能数据:
graph LR A[调度器向APIServer发起请求] --> B[APIServer记录审计日志] B --> C[audit-exporter解析日志] C --> D[转换为Prometheus指标] D --> E[Prometheus抓取存储] E --> F[Grafana查询展示]
核心特点:
- 数据源:kube-apiserver的完整请求审计记录
- 时间精度:基于APIServer的高精度时间戳
- 数据完整性:涵盖从请求到响应的完整生命周期
- 系统开销:不影响调度器性能,仅增加APIServer审计开销
2. 本质差异分析
✅ 数据收集阶段的差异(核心)
传统方法的局限性:
- 可控能力差:调度器内部的metric埋点可能无法覆盖所有关键路径,受制于代码中指标记录调用的位置和频率
- 潜在性能影响:在高负载下,调度器本身指标统计可能会影响调度性能
Audit-exporter方法的优势:
- 可控能力强:可以自定义捕获数据,例如本项目能监控每个API请求的完整生命周期(RequestReceived → ResponseComplete),且因为基于外部 APIServer,所以所有组件(调度器、控制器等)的请求都被统一记录
- 无性能影响:基于外部 APIServer,低侵入性,不影响被监控组件的性能
具体来说,通过audit日志能够精确记录关键事件:
1 | { |
通过解析这些事件,可以计算出精确的 Pod创建延迟、 调度延迟 等数据。
❌ 数据处理阶段的相似性
重要澄清:两种方法在数据处理阶段实际上是相同的!(之前我的博客中,知道数据处理方法中 histogram 会存在误差,但现在才发现这种误差两种方法都会有)
无论是传统方法还是audit-exporter方法,最终都会:
- 将原始数据转换为Prometheus histogram指标
- 使用相同的bucket配置和histogram_quantile()函数
- 面临相同的线性插值误差问题
因此,Prometheus histogram的误差问题在两种方法中都存在,差异并非来自数据处理阶段。
📊 Prometheus Histogram误差深度解析
1. Histogram工作原理
Prometheus histogram通过预定义的bucket边界来统计数据分布:
1 | // 示例:调度延迟histogram配置 |
当收集到延迟数据时,每个观测值会被分配到相应的bucket中:
1 | 观测值: 0.3秒 |
其中 le 指 less,即 bucket 记录“小于 x 的数字有多少个”。
2. 线性插值误差机制
均匀分布假设的问题
Prometheus使用histogram_quantile()
函数计算百分位数时,假设每个bucket内的数据均匀分布:
1 | // Prometheus源码中的线性插值逻辑(简化) |
例子:假设我们有bucket配置[0.1, 0.5, 1.0]
,观测到以下数据:
Bucket范围 | 累计计数 | 实际分布 |
---|---|---|
(0, 0.1] | 10 | 均匀分布 |
(0.1, 0.5] | 90 | 集中在0.12秒附近 |
(0.5, 1.0] | 100 | 均匀分布 |
计算P90(第90个样本):
- Prometheus假设:P90在(0.1, 0.5]区间内均匀分布,计算得P90 ≈ 0.5秒
- 实际情况:如果80个样本都集中在0.12秒附近,真实P90 ≈ 0.12秒
- 结论:存在非常大的误差(尤其当桶边界非线性时,目前看大多数情况下桶边界都是指数级增长,具体原因可能是大部分数据都非均匀分布,数据范围太大时线性分布粒度过粗)
3. Bucket配置的关键影响
默认Bucket的问题
不同Prometheus客户端库的默认bucket配置:
1 | // Go客户端默认bucket |
这些默认配置的问题:
- 覆盖范围过广:从5ms到10s,对特定应用场景分辨率不足
- 分布不均:低延迟区间密集,高延迟区间稀疏
可能的备选Bucket策略
1. 基于SLO设计:
1 | // 假设SLO为P95 < 500ms, P99 < 1s |
2. 对数分布:
1 | // 指数增长,适合跨多个数量级的指标 |
3. 动态调整:某些高级方案支持根据实际数据分布动态调整bucket(VictoriaMetrics似乎有这个功能)
🔧 Histogram替代方案与优化
1. Summary指标
Prometheus提供了Summary类型作为histogram的替代:
1 | summary := prometheus.NewSummary(prometheus.SummaryOpts{ |
优势:
- 客户端精确计算百分位数,无插值误差
- 内存占用相对固定
- 查询性能好
劣势:
- 无法聚合:不能跨实例计算全局百分位数
- 预定义百分位:无法在查询时动态计算其他百分位数
- 客户端开销:需要维护滑动窗口和排序
🔚 总结
通过本文的深入分析,我们可以得出以下关键结论:
核心澄清
数据收集vs数据处理:audit-exporter方法与传统Prometheus方法的主要差异在于数据收集阶段(数据源和精度),而非数据处理阶段(histogram计算)。
Histogram误差本质:Prometheus histogram的误差源于bucket内均匀分布假设与实际数据分布的差异,这在两种方法中都存在。默认bucket配置可能不匹配实际应用的延迟分布,需要根据SLO定制。
- 希望这篇博客对你有帮助!如果你有任何问题或需要进一步的帮助,请随时提问。
- 如果你喜欢这篇文章,欢迎动动小手给我一个follow或star。
📝参考文献
[2] Prometheus中文文档 - Histogram and Summary%E3%80%82)
[4] 蓝胖子编程梦 - prometheus Histogram 统计原理
- 标题: 【集群】云原生批调度实战:Volcano 数据收集方法深度解析与Prometheus Histogram误差问题
- 作者: Fre5h1nd
- 创建于 : 2025-08-10 00:04:35
- 更新于 : 2025-08-21 19:57:43
- 链接: https://freshwlnd.github.io/2025/08/10/k8s/k8s-scheduler-performance-volcano-analysis/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。