【博客685】prometheus 出现NaN场景以及如何去除干扰(Not a Number)

prometheus 出现NaN场景以及如何去除干扰(Not a Number)

1、在prometheus中使用NaN来表示无效数值或者结果

场景:

一些监控系统使用 NaN 作为空值或缺失值,但在 Prometheus 中 NaN 只是另一个浮点值。Prometheus 表示缺失数据的方式是让数据缺失。Prometheus 支持所有 64 位浮点值,包括正无穷大、负无穷大和 NaN。

出现NaN的情况示例:

  • 除以分母0

  • 用作过时处理一部分的标记。

    然而,这是一个实现细节。在过时实现中使用的特定位模式恰好是 NaN,这对 PromQL 用户来说永远是不可见的,尽管远程存储实现如果自己做任何数学运算,可能必须关心这一点。

NaN参数运算时:

因为任何涉及 NaN 的数学都会返回 NaN。根据标准浮点语义,您可以利用 NaN 的独特属性 NaN != NaN。然而,这种情况的用例通常是平均值或分位数的平均值,这两者在统计上都不是有效的。
PromQL 中有些地方对 NaN 值进行了特殊处理,以便行为符合预期。min并max会分别认为 NaN 值大于/小于所有其他数字。sort并且sort_desc实际上并不对称,NaN 总是排在底部。类似地,bottomk和topk将分别认为 NaN 值大于/小于所有其他数字。换句话说,只要你至少有k非 NaN 值,bottomk就topk不会返回 NaN。在某一时刻changes还需要修复错误才能NaN正确处理。

2、如何处理NaN

2-1、即先求和再除。一般来说,总是最后进行除法

不要用:

复制代码
avg by (job)(
    rate(my_sum[5m])
  / 
    rate(my_count[5m])
)

要用:

复制代码
  sum by (job)(rate(my_sum[5m]))
/
  sum by (job)(rate(my_count[5m]))

2-2、如果 NaN 设法进入对值进行数学运算的函数或运算符的输入,则结果将为 NaN。在这种情况下,消除 NaN 的来源,而不是尝试解决下游的不良数据。

注意:这也是为什么部分开源dashboard中,要对源数据取>0就是要过滤掉NaN,以避免由于个别NaN数值,导致整个Sql的结果为NaN

example:

sum (irate (memcached_commands_total{instance="memcached-instance"}[5m])) by (command)

结果:

复制代码
{command="delete"}  0
{command="flush"}   0
{command="get"} 62.733333333333334
{command="incr"}    0
{command="set"} 93.43333333333334
{command="touch"}   NaN
{command="cas"} 0
{command="decr"}    0

sum (irate (memcached_commands_total{instance="memcached-instance"}[5m]))

复制代码
{}  NaN

原因: command="touch"是NaN,因此整个计算是NaN

解决办法: 从计算源中去除NaN

复制代码
sum (irate (memcached_commands_total{instance="memcached-instance"}[5m]) > 0)

3、为什么不设置成 0 , 而设置成 NaN

某些情况下0是正常值,代表某种特殊情况,这样就会混淆

4、Prometheus的函数对NaN处理逻辑:

如果 Metrics 的值里面混有 NaN 的值, 那么会直接污染整个结果, 导致输出的结果就像上面那样, 全部都是 NaN. rate 和 stddev 函数同理

复制代码
// sum
func funcSumOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
    return aggrOverTime(vals, enh, func(values []Point) float64 {
        var sum float64
        for _, v := range values {
            sum += v.V                   // 这里可以看到, 直接累加全部的收集到的 Metrics 的值, 
        }
        return sum
    })
}

// avg
func funcAvgOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
    return aggrOverTime(vals, enh, func(values []Point) float64 {
        var mean, count float64
        for _, v := range values {
            count++
            mean += (v.V - mean) / count  // 这里也是类似, 把和现在差值直接加上去
        }
        return mean
    })
}

max 和 min 函数不受影响:

复制代码
// Max
func funcMaxOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
    return aggrOverTime(vals, enh, func(values []Point) float64 {
        max := values[0].V
        for _, v := range values {
            if v.V > max || math.IsNaN(max) {  // 过滤 NaN
                max = v.V
            }
        }
        return max
    })
}

// Min
func funcMinOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
    return aggrOverTime(vals, enh, func(values []Point) float64 {
        min := values[0].V
        for _, v := range values {
            if v.V < min || math.IsNaN(min) {  // 过滤 NaN
                min = v.V
            }
        }
        return min
    })
}
相关推荐
云游2 天前
大模型性能指标的监控系统(prometheus3.5.0)和可视化工具(grafana12.1.0)基础篇
grafana·prometheus·可视化·监控
qq_232045573 天前
非容器方式安装Prometheus和Grafana,以及nginx配置访问Grafana
nginx·grafana·prometheus
夜莺云原生监控3 天前
Prometheus 监控 Kubernetes Cluster 最新极简教程
容器·kubernetes·prometheus
SRETalk4 天前
Prometheus 监控 Kubernetes Cluster 最新极简教程
kubernetes·prometheus
川石课堂软件测试4 天前
JMeter并发测试与多进程测试
功能测试·jmeter·docker·容器·kubernetes·单元测试·prometheus
SRETalk5 天前
夜莺监控的几种架构模式详解
prometheus·victoriametrics·nightingale·夜莺监控
Ditglu.6 天前
使用Prometheus + Grafana + node_exporter实现Linux服务器性能监控
服务器·grafana·prometheus
SRETalk6 天前
监控系统如何选型:Zabbix vs Prometheus
zabbix·prometheus
睡觉z6 天前
云原生环境Prometheus企业级监控
云原生·prometheus
归梧谣6 天前
云原生环境 Prometheus 企业级监控实战
云原生·prometheus