为什么首先聊监控指标

📅 2026/6/29 0:51:11
为什么首先聊监控指标
作为高可用系列的第一篇。一开始我是想写一个非常宏大的体系大纲但一方面我还没想好怎么设计另一方面我觉得首篇只抛一个框架出来其实有点空泛。所以我就先写一点实际的也是我这几年认识比较深刻的地方吧。熟悉我的人都知道我非常喜欢troubleshooting这几年令我印象深刻的问题都是对于监控指标的解读出了问题所以在高可用这一块认识监控指标的局限性其实是非常重要的毕竟监控是我们的眼睛:)监控指标反映的只是真实的投影监控指标通常是展示采集的数据(Count/Guage等)或对采集的数据运算(QPS/TPS等)。例如我们最常见的指标QPS其含义是平均一秒内有多少次请求。其公式就是:QPS请求总数/总时间这么简单的一个公式其实就蕴含着不小的复杂性。 在公式的分子上-请求总数就很有说法这个请求总数是分布在一台机器上还是在多台机器上。用总数来表达其实就丢失了空间上的分布信息从向量坍缩成了标量是一种投影如下图所示:在公式的分母上-总时间这个也有说法很多监控系统都做不到秒级监控而是分钟级那么100qps可能是均匀的分布在一分钟之内(秒级100)也有可能是仅仅只分布在一秒(秒级6000)内。用60s来计算其实就丢失了时间上的分布信息又是从向量坍缩成了标量又是一种投影如下图所示:在公式的分母上-总时间其实还有其它的变化。例如监控系统每5s采样一次计算出请求总数。但是监控系统本身由于GC的STW或者load高等原因并不是5s精确采样而是漂移到第6s。但分母依旧是用5s来进行计算那么毫无疑问QPS会被计算的偏高如下图所示:为了避免这种现象我们的公式可以修改为:QPS请求总数/时间差如果这个时间差的计算采用墙上时钟(也就是WallClock)那么会由于和NTP授时同步的时候由于时钟跳变(往前或往后拨数秒)而导致QPS的运算出现偏差如下图所示:所以我们需要使用monotonic clock(单调时钟来进行计算)。但即使是如此也无法保证采样任务一定在精确的5s后运行。请求总数丢失了空间分布总时间丢失了时间分布。一旦做了 QPS 这个运算原本“机器维度 × 时间维度”的二维矩阵就被压缩成了一个标量。这个标量当然有用但它已经不是系统真实运行过程本身它只是真实的投影。监控指标无法衡量超出它精度的真实那么如果仅仅只记录数据本身而不做计算是不是能够精确的反映系统的运行过程呢。有时候也不行因为数据本身是有精度的超过这个数据的精度能表达的上限依旧无法反映真实。例如我们最常用的主从延迟指标Seconds_behind_master它的精度是秒。无论监控如何踩点它的原始数据只有0/1/2等整数例如下图所示:笔者就遇到过这样的现象两个一模一样的从库一个从库采样取点基本是0看上去去平均延迟为20ms另一个从库一半的取点为1看上平均延迟为500ms。实际这两的主库延迟是基本一样的远没有(500-20)480ms这样的差距。这其实就和Seconds_behind_master精度只到秒有关。让我们自己观察一下Seconds_behind_master的计算公式:long time_diff ((long)(time(0) - mi-rli-last_master_timestamp) - mi-clock_diff_with_master);关键点在于这个clock_diff_with_master。这边需要先引入一个容易被忽略的常识那就是不同机器的时间戳是不一致的。所以我们在计算Seconds_behind_master的时候需要去掉时间戳不一致的影响也即减去clock_diff_with_master。这个clock_diff_with_master的精度也是秒那么在处理毫秒为单位的时间戳的时候势必存在精度损失。同时这个clock_diff_with_master只会在主从连上的那一刻只计算一次。计算完之后这个精度损失导致的数据差距会一直存在例如我们假设在计算clock_diff_with_master的那一瞬间。从库的clock是0.5s主库的clock是1.0s那么他们的时间差就会由于精度的原因从0.5s放大到1s(MySQL源码中会进行四舍五入)。而这0.5s就会导致实际主从延迟为0的从库在监控指标看来是500ms。计算过程如下图所示:在上图中我们可以看到在我们取从库时钟[0.5,1.5)这个1s的时间段范围内。在前0.5s也就是[0.5,1)这个区间中我们计算出来的Seconds_behind_master是-1然后由MySQL源码强行校正为0而在[1,1.5)区间计算的确是1 。那我们的平均值就可以计算出来为(0.5*00.5*1)/(1.5-0.5)0.5500ms!从上面这个例子就可以看到用只有秒级的监控指标来观测毫秒级的主从延迟差距完全没有意义Seconds_behind_master这个指标只能反映秒级的变化。它只能回答“有没有秒级延迟”这个问题不能拿来回答“有没有几百毫秒延迟”这个问题。指标一旦被拿去回答超出它表达精度的问题就会从工具变成误导。如果想看详细的分析可以看笔者之前的文章:https://mp.weixin.qq.com/s/YBLxEPbaNAYxjUYGhmIl_g监控指标无法突破采集环境的边界那么如果我拥有无限的精度能否精确的反映系统的运行过程呢有时候也不能做到因为指标是在环境中采集的环境本身限制了它的表达。例如在容器中cpu busy的计算是 :容器运行的时间/总时间 注:实际可能是 CPU.busy (cpuacct.usage(T秒) - cpuacct.usage(T-5秒))/((5秒)*CPU核数)如果容器中监控指标CPU.busy50%就认为系统还处于健康水位就很有可能被误导。在容器超卖(例如64核的物理机分配了总共128核的容器应用)。在所有应用都很繁忙的情况下容器中的CPU.busy最多只能达到50%就被其它繁忙的容器抢占。物理机CPU利用率可能已经到了100%而容器的CPU只能到50%。如下图所示: