prometheus专题—(八)线性插值法原理和summary

本文涉及的产品
可观测监控 Prometheus 版,每月50GB免费额度
简介: 前言● prometheus官方文档中对于两种类型的对比说明 下面我总结了一些对比点

前言

     下面我总结了一些对比点

image.png

histogram 线性插值法

histogram_quantile为何需要先算rate

  • 因为每个bucket都是`counter`型的,如果不算rate那么分位值的结果曲线是一条直线
  • 原理是因为`counter`型累加,不算rate并不知道当前bucket的增长情况,换句话说不知道这些bucket是多久积攒到现在这个值的

什么是线性插值法

- 之前阅读很多文章都提到`histogram`采用`线性插值法`计算分位值会导致一定的误差
- 对这个`线性插值法`总是理解的不到位
- 在查看完代码之后明白了

代码分析

- 代码位置:`D:\work\go_work\pkg\mod\github.com\prometheus\prometheus@v0.0.0-20201209205804-66f47e116e00\promql\quantile.go`
### 

bucket数据结构

- 其中`bucket` 代表事先定义好的bucket
- `upperBound`代表这个bucket的上限值
- `count` 代表这个小于等于这个`upperBound`的个数/次数
- `workqueue_work_duration_seconds_bucket{name="crd_openapi_controller",le="10"} 65246 `
- 所以上述表达式含义为 `workqueue_work_duration_seconds`小于`10`秒的有`65246 `个
type bucket struct {
  upperBound float64
  count      float64
}
type buckets []bucket
func (b buckets) Len() int           { return len(b) }
func (b buckets) Swap(i, j int)      { b[i], b[j] = b[j], b[i] }
func (b buckets) Less(i, j int) bool { return b[i].upperBound < b[j].upperBound }

核心计算函数

func bucketQuantile(q float64, buckets buckets) float64 {
  if q < 0 {
    return math.Inf(-1)
  }
  if q > 1 {
    return math.Inf(+1)
  }
  sort.Sort(buckets)
  if !math.IsInf(buckets[len(buckets)-1].upperBound, +1) {
    return math.NaN()
  }
  buckets = coalesceBuckets(buckets)
  ensureMonotonic(buckets)
  if len(buckets) < 2 {
    return math.NaN()
  }
  observations := buckets[len(buckets)-1].count
  if observations == 0 {
    return math.NaN()
  }
  rank := q * observations
  b := sort.Search(len(buckets)-1, func(i int) bool { return buckets[i].count >= rank })
  if b == len(buckets)-1 {
    return buckets[len(buckets)-2].upperBound
  }
  if b == 0 && buckets[0].upperBound <= 0 {
    return buckets[0].upperBound
  }
  var (
    bucketStart float64
    bucketEnd   = buckets[b].upperBound
    count       = buckets[b].count
  )
  if b > 0 {
    bucketStart = buckets[b-1].upperBound
    count -= buckets[b-1].count
    rank -= buckets[b-1].count
  }
  sql:=fmt.Sprintf("%v+(%v-%v)*(%v/%v)",
    bucketStart,
    bucketEnd,
    bucketStart,
    rank,
    count,
  )
  log.Println(sql)
  return bucketStart + (bucketEnd-bucketStart)*(rank/count)
}

我们现在有这些数据,然后求75分位值

a := []bucket{
    {upperBound: 0.05, count: 199881},
    {upperBound: 0.1, count: 212210},
    {upperBound: 0.2, count: 215395},
    {upperBound: 0.4, count: 319435},
    {upperBound: 0.8, count: 419576},
    {upperBound: 1.6, count: 469593},
    {upperBound: math.Inf(1), count: 519593},
}
q75 := bucketQuantile(0.75, a)
- 其计算逻辑为:根据记录总数和分位值求目标落在第几个bucket段`b`
- 根据`b`得到起始bucket大小`bucketStart`,终止bucket大小`bucketStart` ,本bucket宽度 ,本bucket记录数
- 根据本段记录数和分位值算出目标分位数在本bucket排行`rank`
- 最终的计算方式为`分位值=起始bucket大小+(本bucket宽度)*(目标分位数在本bucket排行/本bucket记录数)`
- 换成本例中: `q75=0.4+(0.8-0.4)*(70259.75/100141) = 0.6806432929569308`
2021/02/02 19:08:55 记录总数 = 519593
2021/02/02 19:08:55 目标落在第几个bucket段= 4
2021/02/02 19:08:55 起始bucket大小= 0.4
2021/02/02 19:08:55 终止bucket大小= 0.8
2021/02/02 19:08:55 本bucket宽度= 0.4
2021/02/02 19:08:55 本bucket记录数= 100141
2021/02/02 19:08:55 目标分位数在本bucket排行= 70259.75
2021/02/02 19:08:55 分位值=起始bucket大小+(本bucket宽度)*(目标分位数在本bucket排行/本bucket记录数)
2021/02/02 19:08:55 0.4+(0.8-0.4)*(70259.75/100141) = 0.6806432929569308

那线性插值法的含义体现在哪里呢

- 就是这里 `本bucket宽度*(目标分位数在本bucket排行/本bucket记录数)`
- 有个假定:样本数据这个目标bucket中按照平均间隔均匀分布
- 举例 100141个样本在0.4-0.8 bucket中均匀分布
- 如果真实值分布靠近0.4一些,则计算出的值偏大
- 如果真实值分布靠近0.8一些,则计算出的值偏小
- 这就是线性插值法的含义

histogram 高基数问题

具体可以看我之前写的文章prometheus高基数问题和其解决方案

危害在哪里

- 一个高基数的查询会把存储打挂
- 一个50w基数查询1小时数据内存大概的消耗为1G,再叠加cpu等消耗
### 

为何会出现

  • label乘积太多 ,比如bucket有50种,再叠加4个10种的业务标签,所以总基数为 50*10*10*10*10=50w


summary 流式聚合

一个qps为1万的http服务接口的分位值如何计算

  • 假设以1秒为窗口拿到1万个请求的响应时间,排序算分位值即可
  • 但是1秒窗口期内,快的请求会多,慢的请求会少
  • 原理分析:说来惭愧,没看太明白,但是可以确定就是hold一段时间的点计算的
  • 使用库"github.com/beorn7/perks/quantile"
  • 感兴趣的可以自己研究下D:\work\go_work\pkg\mod\github.com\prometheus\client_golang@v1.9.0\prometheus\summary.go
相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
相关文章
|
Prometheus 监控 Cloud Native
Prometheus Operator配置原理
Prometheus Operator配置原理
90 0
|
存储 Prometheus 监控
Prometheus的架构原理,如何使用其进行监控告警配置实现?
Prometheus的架构原理,如何使用其进行监控告警配置实现?
365 0
Prometheus的架构原理,如何使用其进行监控告警配置实现?
|
存储 数据采集 Prometheus
Prometheus原理简介
充分了解Prometheus原理
615 0
Prometheus原理简介
|
16天前
|
Prometheus 运维 监控
智能运维实战:Prometheus与Grafana的监控与告警体系
【10月更文挑战第26天】Prometheus与Grafana是智能运维中的强大组合,前者是开源的系统监控和警报工具,后者是数据可视化平台。Prometheus具备时间序列数据库、多维数据模型、PromQL查询语言等特性,而Grafana支持多数据源、丰富的可视化选项和告警功能。两者结合可实现实时监控、灵活告警和高度定制化的仪表板,广泛应用于服务器、应用和数据库的监控。
90 3
|
3月前
|
Prometheus 监控 Cloud Native
【监控】prometheus传统环境监控告警常用配置
【监控】prometheus传统环境监控告警常用配置
【监控】prometheus传统环境监控告警常用配置
|
6天前
|
Prometheus 监控 Cloud Native
在 HBase 集群中,Prometheus 通常监控哪些类型的性能指标?
在 HBase 集群中,Prometheus 监控关注的核心指标包括 Master 和 RegionServer 的进程存在性、RPC 请求数、JVM 内存使用率、磁盘和网络错误、延迟和吞吐量、资源利用率及 JVM 使用信息。通过 Grafana 可视化和告警规则,帮助管理员实时监控集群性能和健康状况。
|
15天前
|
Prometheus 运维 监控
智能运维实战:Prometheus与Grafana的监控与告警体系
【10月更文挑战第27天】在智能运维中,Prometheus和Grafana的组合已成为监控和告警体系的事实标准。Prometheus负责数据收集和存储,支持灵活的查询语言PromQL;Grafana提供数据的可视化展示和告警功能。本文介绍如何配置Prometheus监控目标、Grafana数据源及告警规则,帮助运维团队实时监控系统状态,确保稳定性和可靠性。
80 0
|
2月前
|
Prometheus 监控 Cloud Native
介绍如何使用Prometheus进行监控
介绍如何使用Prometheus进行监控
197 3
|
2月前
|
Prometheus 监控 Cloud Native
docker安装prometheus+Granfan并监控容器
【9月更文挑战第14天】本文介绍了在Docker中安装Prometheus与Grafana并监控容器的步骤,包括创建配置文件、运行Prometheus与Grafana容器,以及在Grafana中配置数据源和创建监控仪表盘,展示了如何通过Prometheus抓取数据并利用Grafana展示容器的CPU使用率等关键指标。
|
3月前
|
存储 Prometheus 监控
Grafana 与 Prometheus 集成:打造高效监控系统
【8月更文第29天】在现代软件开发和运维领域,监控系统已成为不可或缺的一部分。Prometheus 和 Grafana 作为两个非常流行且互补的开源工具,可以协同工作来构建强大的实时监控解决方案。Prometheus 负责收集和存储时间序列数据,而 Grafana 则提供直观的数据可视化功能。本文将详细介绍如何集成这两个工具,构建一个高效、灵活的监控系统。
397 1