监控全绿,线上还是抖了一下——加埋点只能解决三种"看不见"里的一种

先说结论,三条:

  1. 现象 :「全部指标正常」这句话的真实含义只有一句------我盯着的那几个数,在这一刻、按我选的这个聚合方式、没出事。它不等于系统没事。
  2. 根因 :「全绿却抖」不是一个问题,是三个不同的问题混在同一块绿色仪表盘后面:没埋点的地方 (覆盖缺口)、埋了点但被聚合抹平的地方 (维度坍缩)、点了也测不对的地方(语义不等价 + 局部自治)。
  3. 方向:加埋点只能治第一种。第二种要下钻维度,第三种要换信号源(端到端断言 + 旁路观测)。三种不加区分,你的第一反应就一定是错的------继续加指标,绿色面积更大,盲区一寸没少。

一、先把现场压到 200 字

老赵四十七,跑长途十九年。九十码方向盘轻轻摆,副驾杯架里的水杯"哒哒"响,降到八十就没了。空车不显,重车明显。

4S 店插电脑:"无故障码。"动平衡、四轮定位、换两条前胎,一千四花完,上高速还是响。

国道边一个没电脑的修车铺。老吴拿手电照一遍,摸右前轮慢慢转,一根半米长的铁杆顶在羊角上、一头贴着耳朵听,二十分钟:「右边半轴里那个球笼,滚珠槽磨出台阶了。跑直路不显,一带方向就顶一下。」

「电脑怎么不报?」

「那个球笼上没有传感器。它坏了,也没人替它说话。」

一百七换掉,到九十码,水杯不响了。


二、素材里这句话是错的,得先拆掉

「它坏了,也没人替它说话」很动人,但如果你把这句直接搬到线上,会得出一个错误的第一反应:全绿却抖 = 我埋点不够,加埋点。

我见过太多团队就这么干:告警不响,那就再加二十个指标。仪表盘从两屏变六屏,全绿的面积更大了,问题一次没少。

因为「全绿却抖」在软件系统里有三个完全不同的成因,只有第一个是"没装传感器"。

用素材自己的话拆一遍:车上零件数以万计、传感器几百个,覆盖率是百分之一量级------这是第一种看不见。可就算你把覆盖率做到 100%,还有两件事在等着你:

  • 传感器确实装了,但它报上来的是一个被平均过的数。一个传感器的读数是事实,一万个传感器的平均值是一种意见。
  • 传感器测的不是你要的那个东西 。水温正常不代表没拉缸;/healthz 返回 200 不代表业务是对的。

所以严格版本是这一句:

「全绿」不是在描述系统,是在描述你的观测装置。 你要判断的从来不是"绿不绿",而是"这套观测装置在多大范围、按什么聚合、测的是不是我要的那个量"。

三种,下面一条一条拆,每种给一条能直接跑的量化判据。


三、三种「看不见」

类型一:覆盖缺口------真的没装传感器

现象:故障发生在没有任何埋点的路径上。没打点的老代码、第三方依赖内部、内核/网络层、异步补偿任务、定时任务、迁移脚本、运维手动执行的命令。

为什么是必然不是偶然 :埋点跟着业务代码走,业务代码跟着需求走。没需求的地方就没有埋点,而故障不看需求表。更扎心的是:写代码的人不会给自己的疏漏打点。

量化判据(这条今天就能跑):同一时间窗,比两个数------

  • 分子:服务端埋点里看到的请求数
  • 分母:网关 / sidecar / 内核层(eBPF、tcpdump、ss)看到的请求数
text 复制代码
埋点请求数 / 网关请求数 < 0.98   →  2% 以上的路径在盲区里

这不是"大概",是减法。差额部分就是你的盲区清单,而且这个差额通常稳定存在------它不是抖动,是结构。

类型二:维度坍缩------装了传感器,但被聚合抹平

这类最容易骗人,因为乱不是发生在数据里,是发生在你的聚合方式里。三个典型:

(a)平均值吃掉长尾。 10 个租户均分流量,其中 1 个租户(跑大报表)的每个请求都是 4 秒,其余 9 个租户 50ms:

指标 值 读者会怎么理解
P50 50ms 「大部分很快」
平均 445ms 「还行,在 SLA 500ms 以内,绿的」
P99 4000ms 「有 1% 慢一点」

三个数讲三个故事。而仪表盘默认画的是哪一个?平均值 。真实情况是:10% 的用户,每一次请求都在等 4 秒。他们的体验在平均值里被稀释了 8.9 倍。

(b)全局分母稀释。 灰度期最典型:新版本占 1% 流量,错误率已经 10%,全局错误率只涨 0.1 个百分点------正好卡在告警阈值下面。公式简单到残忍:

全局错误率 ≈ Σ(流量占比 × 分组错误率)

某组流量占比 p,该组错误率变化 Δe,对全局的贡献只有 p × Δe 。p = 1% 时,新版本彻底烂掉(Δe = 10%)也只能让全局动 0.1%。灰度越小,越看不见。 而新版本烂掉,恰恰是你最该在看到的那件事。

(c)时间窗错位。 5 分钟粒度的指标和 1 分钟粒度的日志对不上,你会在错误的窗口里找错误的原因,然后得出"指标正常、日志报错、日志系统有问题"这种结论,白查两天。

量化判据 :对每个关键指标,每小时自动跑一次全维度 group by(instance / version / region / tenant / endpoint),比较最差分组和全局:

sql 复制代码
-- 伪代码,按你的 TSDB 改写。目的:找出被全局数字盖住的那一组
SELECT metric, group_key,
       quantile(0.99)(value)  AS group_p99,
       sum(value)             AS group_traffic
FROM   metrics_1m
WHERE  ts > now() - interval '1 hour'
GROUP  BY metric, group_key
HAVING quantile(0.99)(value) > 3 * global_p99(metric)
  • 最差分组 P99 ÷ 全局 P99 > 3 → 聚合已失真,这块仪表盘不能再当结论用
  • 最差分组错误率 ÷ 全局错误率 > 3 ,且该组流量占比 < 5% → 全局指标对这组结构性失明

类型三:语义不等价 + 局部自治------测了,但测的不是你要的

(a)代理变量不等于结果。 四黄金信号(延迟 / 流量 / 错误 / 饱和度)测的是"系统在动",不是"业务对了"。返回值 200、DB 连接正常、CPU 30%------而 ETL 三天前就停了,页面显示的是三天前的数据,所有实例 healthy。仪器全准,量错了东西。

(b)局部自己做了决定,账记在别人头上。 这正是素材里那句「有些局部,是自己做决定的」在软件里的样子:

  • 重试 :三层各重试 3 次,最坏 27 倍 放大。上游指标只记了 1 次失败,下游被打了 27 次。重试不是不上报,是报在别人的账上。
  • 连接池:自己回收、自己重建、自己预热,你只看到"连接数正常"。
  • GC、异步补偿、消息重投、sidecar 健康剔除:都在主链路埋点之外自己决策,做对了不告诉你,做错了也不走你的错误率。

量化判据:

text 复制代码
下游入口 QPS / 上游请求数 > 1   → 存在放大
                        > 3   → 必须查是哪一层的重试在叠

数据新鲜度 = now - 最新一条数据的业务时间戳
数据新鲜度 > 预期更新周期 × 2   → 告警(这一条能抓住绝大多数"全绿但用户在吃旧数据")

四、三条验法(每条都带证伪条件)

验法 A:两路对照------把耳朵贴到没装耳朵的地方

老吴不是比电脑聪明,他是把耳朵贴到了电脑没装耳朵的地方。工程上就是两套互不依赖的观测,对同一段时间:

  1. 内部:服务端埋点(你已有的 metrics / trace)
  2. 外部:网关日志、eBPF / syscall 层计数、客户端 RUM 或合成探针

记录什么 :同一 5 分钟窗内的请求数、P99、错误数,两组各一份。 判据 :请求数差 > 2%,或 P99 差 > 20% → 两组里至少有一组在说谎。先查清是哪组,再谈"系统正常"。 证伪:如果两路在连续 24 小时、跨一次发布前后都对得上(差 < 1%),那你的覆盖缺口基本不存在,这条验法对你无效,可以划掉。

验法 B:维度下钻扫描------治聚合坍缩

别靠人肉看板。写个每小时跑的脚本,对每个关键指标拉全维度分组,算"最差分组 / 全局"的比值,超阈值就出一条报告(先别做成告警,看一周再决定要不要吵醒人)。

记录什么 :指标名、分组维度、最差分组值、全局值、比值、该组流量占比。 判据 :比值 > 3 且连续 3 个周期成立 → 这条指标的仪表盘已经失真。 证伪:下钻一周后所有比值都 < 1.5 → 你的流量结构和聚合方式本来就是安全的,频率调低或停掉。

验法 C:端到端业务断言------治语义不等价

把"健康"从形容词改成断言。合成探针不只请求首页拿 200,而是走完整业务链路,检查结果对不对:

python 复制代码
# 健康 ≠ 200。三个断言,缺一个都只是"它在动"
assert resp.status_code == 200
assert resp.json()["id"] == test_id                      # 结果对
assert now() - resp.json()["data_time"] < 2 * PERIOD     # 数据新

记录什么 :HTTP 2xx 率、业务断言通过率、数据新鲜度滞后。 判据 :2xx 率 − 业务断言通过率 > 0.1% → 存在语义缺口,你的 2xx 在替失败背书。 证伪:两条曲线长期重合(差 < 0.01%)且数据滞后稳定在预期内 → 你的健康检查已经是语义级的,这条对你无效。


五、工程落地:三件能直接塞进流程的事(从弱到强)

第一件:证据锚定(最弱,但今天就能做) 告警和工单里禁止只写"指标正常"。要求贴三样:查询语句、时间窗、带维度的原始时间序列截图。能被复查的结论才叫结论,不能复查的只是感觉。几乎零成本,能挡掉一半"我觉得没问题"。

第二件:可执行验证 把"正常"写成代码:合成探针带业务断言、数据新鲜度断言、对账任务(订单数 vs 支付数 vs 发货数,差值超阈值即报)。凡是能用一次查询或一次请求判定的健康,都不要留给人的判断。

第三件:独立校验器(最强) 监控不能是被监控系统的一部分。旁路一套不受主链路影响的观测:网关侧日志、内核层计数、客户端真实用户监测。当主链路说"我很好"而旁路说"不对",信旁路。 顺带说一句:这和"让系统自己检查自己"是同一类结构问题------检查者和被检查者是同一个,结论必然偏,所以判据必须外置。


六、边界三条(这套说法什么时候不成立)

  1. 没有 SLO 的系统不值得做到这一步。 内部工具、低频后台,观测成本远超故障损失。日志兜底 + 人肉看,够了。
  2. 有一部分确实物理不可观测。 未导出的进程内部状态、被编译器优化掉的路径、加密流量里的业务语义------你只能说"在这一层看不见",不能反推"必有隐藏故障"。"测不到"不等于"有",把这句话反过来用就是阴谋论。
  3. 这套判断假设你有权改埋点和探针。 闭源 SaaS、第三方依赖只能用黑盒对照(验法 A 的外部那一路),结论强度下降一档,判据容差要放宽。

递刀口:如果你的系统已经按 tenant / version / instance 全维度拆分,已有端到端业务断言,还有一套独立旁路观测------那"全绿却抖"这套描述对你不成立,你尽管把它划掉。真到那一步,你用的一定是别的东西在发现问题。欢迎在评论区说说你用的是什么,我也想学。


七、最后一句

老赵说换完球笼那一刻不是高兴,是有点后怕------那个东西磨了多久,他不知道。他一直以为"电脑说没事"就是没事。

工程上对应的一句话是:"监控说没事"只等于"我的观测装置没报",不等于"系统没事"。 你能做的不是把窗口擦得更亮,是知道这扇窗朝着哪边、玻璃有多厚、窗外还有多少你没看的地方。

把「监控全绿」「看不见」「局部自治」这些平时说不清的东西说清楚,是结构认知 一直在做的事。上面这条推导,出自《仪表盘全绿,车还是在高速上抖了一下》,第一发现者:林小黑。完整推导见 gitee.com/samforce/st...。

相关推荐
琳达爱分享1 小时前
五个线程同时去换 token,四个被踢下线:刷新接口其实不是幂等的
后端·算法·架构
第404号工位1 小时前
插上充电宝真能偷光相册?我拆解了一台改装充电宝,实测“恶意充电”的真实攻击链
linux·python·架构
数据库小学妹1 小时前
MySQL表碎片与 OPTIMIZE TABLE:空间回收的代价与边界
数据库·后端·mysql
故图1 小时前
全字段 INSERT IGNORE:大约 70 行零日期,把证照列表加载打崩
后端
Json____1 小时前
用 FastAPI + Vue3 打造一套健身私教课预约管理系统
后端·fastapi·it学习·wwwoop.com
aibo8603081 小时前
基于 Spring Boot + Vue3 的博物馆藏品管理系统设计与实现
java·spring boot·后端
苍何1 小时前
Codex+Obsidian,多平台同步,一键分发,太香了!
后端
幻智星科技1 小时前
FPGA不同品牌开发平台约束文件迁移难题解析
fpga开发·架构·硬件架构
zzu123zsw2 小时前
把条件校验收敛到枚举接口:Spring Boot 统一断言模式与零污染异常切面工程化
java·spring boot·后端·架构设计