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 函数同理文章来源:https://www.toymoban.com/news/detail-627771.html
// 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 函数不受影响:文章来源地址https://www.toymoban.com/news/detail-627771.html
// 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
})
}
到了这里,关于【博客685】prometheus 出现NaN场景以及如何去除干扰(Not a Number)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!