Grafana 使用 histogram_quantile 和 rate 的精度问题

Grafana 上如果观测离群点,会发现它的值漂移地很厉害。往往一个实际 2min 的指标能显示出是几个 hour。
https://github.com/pingcap/tiflash/issues/8076 所述。这个问题发生需要同时使用 histogram_quantile 和 rate。

此外,可以从这个解决方案延伸出一个浮点压缩算法 ALP。

其原因是 rate 会将 count 除成小数,因为 IEEE 浮点数不能精确表示,所以引入了噪音数据。
如下所示,8.192 和 67108.864 这两个桶对应的 sum 应该是相等的。但因为浮点数加法的问题,它们不相等了。因此这些立群值就会被放到 bucket 序号更大的桶里面了。

https://github.com/m3db/m3/issues/3706

The problem is that the rate function, while doing its magic, turns counts into fractions. Most fractions can’t be expressed exactly as a floating point number (IEEE754 standard). The resulting number that represents the fraction is just an approximation that uses up all bits of mantissa.

因为精度的问题,导致在某个 edge 上会进一位。所以可以用 histogram_quantile(1.0, sum(round(1000000000*rate(xxx{}[5m]))) by (le) / 1000000000) 这样来规避。

这也体现出浮点数的性质不咋样,连结合律都不满足。在工程上来讲,不满足结合律意味着没法分治。

ALP 压缩算法

这个算法是给浮点数乘一个 10**e 让它变成一个整数。从上面可以知道,这个 e 可能要远大于实际的小数位数,才能在除回来之后是无损的。为了免于存储后面大量的 0,算法还引入一个 f,表示最后 f 个零,我们就不放在整数里面了。

但是经过同事测试,选择 vector 长度为 10k,exceptional vector 的长度确实是有限的大约在 800 左右,说明选择合适的 e 和 f 还是能取得比较好的覆盖率的。但是实际压缩率只有 0.5,这是非常差的成绩,就算按照 (e,f,int) 三个 int 换一个的方式压缩,都不至于这么低。据说这是因为对 integer 的 bitpacking 压缩效率不是很高。这里原因是 f32 也是会被编码为 u64 的,所以后面很依赖 bitpacking 的压缩。