Prometheus说"我很好",但我总觉得哪里不对:一次沉默的监控失效
Prometheus说”我很好”,但我总觉得哪里不对:一次沉默的监控失效
说出来你们可能不信,今天我发现了一个所有监控系统的终极悖论:监控系统告诉你一切正常,但实际上是监控系统本身出了问题。
对,你没听错。
Prometheus 的状态页面显示”一切正常”,targets 接口返回的状态是”healthy”,但实际上有一半的监控目标已经失联超过 48 小时了——而我浑然不知。
这就是今天的故事。
早上10点:我发现了一个奇怪的现象
今天上午,我正在例行检查监控系统。打开 Grafana,看了一眼仪表盘,一切都是绿色的。Prometheus 的 targets 页面显示 34 个目标,全部 up。
作为一个在上海当了几年运维的人,我看到这种”完美状态”的第一反应不是开心,而是——不对劲。
为什么?因为我太清楚我的服务器们是什么德性了。它们从来不会集体表现良好,总是有那么几个在闹脾气。
我决定深挖一下。
第一步:Prometheus说一切正常,但我有疑虑
我先查了一下 Prometheus 的告警规则。告警列表:空的。targets 状态:全部 healthy。服务运行时间:17天。
看起来没什么问题。
但我还是打开 Targets 页面看了一眼。结果我发现了一件事:最后一批 targets 的采集时间是 48 小时前。
等等,48 小时前?那不就是前天吗?
我再看了一遍,确信没看错。最后一次成功采集的时间戳显示的是两天前的某个时间点,而现在已经超过 48 小时没有任何新的数据了。
但奇怪的是,Prometheus 的状态页面依然显示所有目标为 up。
第二步:去Grafana验证一下
我打开 Grafana,找到了一个 CPU 使用率的仪表盘。正常情况下,Grafana 应该显示实时的 CPU 数据,图表应该是”流动”的——右端是最新数据,左端是历史数据。
但我看到的图表,右端是平的。
没有任何新的数据点。
我选了最近 1 小时的数据范围,结果——一片空白。不是零,是完全没有数据。
这就很奇怪了。Prometheus 明明说 targets 全 up,为什么 Grafana 拿不到数据?
第三步:手动测试抓取
我在 Prometheus 服务器上跑了一个手动抓取测试,结果很有意思:
lastError: 空lastScrape: 48 小时前health: up
好家伙。health: up 但 lastScrape 是 48 小时前。这两个概念在 Prometheus 里居然是分开的——health 表示目标本身是否可达,lastScrape 表示最后什么时候抓的数据。
问题是:Prometheus 认为目标可达,所以 health 显示 up,但因为某种原因,抓取任务本身停了,所以没有新的数据进来。
第四步:检查Prometheus的抓取配置
我开始排查 Prometheus 的抓取配置。配置看起来很正常:15秒一次抓取,targets 列表里也确实有那些服务器。
配置没问题。
第五步:检查Prometheus日志
我去看了 Prometheus 的日志。日志里出现了这个:
1 | |
“persistence queue is full”。持久化队列满了。
这个错误信息告诉我:Prometheus 在尝试写入数据的时候,发现队列满了,写不进去。于是它跳过了这次抓取。但因为目标是可达的(网络没问题),所以 health 依然显示 up。
这就是那个”沉默的失效”——错误没有触发告警,因为 Prometheus 认为这不是”目标 down”,只是”写入失败”。
根因找到了:磁盘I/O瓶颈
我顺着日志继续查,发现了更多的错误:
1 | |
“No space left on device”。磁盘空间不足。
这下真相大白了:
- Prometheus 的数据目录所在的磁盘空间不足(或者 I/O 瓶颈)
- Prometheus 无法写入新的数据
- 为了防止内存溢出,Prometheus 跳过了抓取周期
- health check 依然认为目标可达(因为网络没问题)
- 但实际上没有任何新数据进来
这个”沉默的失效”持续了 48 小时,直到我今天碰巧去 Grafana 看图表才发现。
修复过程
找到根因就好办了。我先清理了一些旧的监控数据,重启了 Prometheus 服务:
1 | |
然后我等了几分钟,再去看 Grafana——图表终于开始流动了。
最新数据进来了。
中午:顺便查了一下其他告警配置
既然发现了这个问题,我就顺便检查了一下其他告警规则——Prometheus 会不会有其他”沉默的失效”场景?
还真找到了一个相关规则。这个规则只检查 up == 0,也就是目标完全不可达的情况。但它不会检查”目标可达但数据停止更新”的情况。
换句话说:Prometheus 的默认告警规则没有覆盖”数据停滞”这个场景。
下午:新增了一个告警规则
既然发现了漏洞,我就补上了。
我在告警规则里加了一条新的告警:
1 | |
这条规则的逻辑是:如果当前时间减去最后一次抓取时间,大于两倍的抓取间隔,就触发告警。
这样下次再出现类似的”数据停滞”问题,我就能第一时间知道了。
晚上:总结今天的感悟
今天的故事说起来不复杂:Prometheus 的磁盘满了,导致数据抓取停滞,但因为目标是可达的,所以健康检查依然通过,告警没有触发。
这个故事告诉我们几个道理:
第一,监控本身也需要被监控。
我们通常会给服务器、应用、数据库加上监控,但很少会监控”监控系统本身”是否正常工作。Prometheus health 页面显示 up,不代表它的抓取任务在正常工作。你得看实际的数据流,得看图表有没有新数据,得看 lastScrape 时间戳。
第二,”一切正常”往往是最危险的状态。
我看到 Grafana 全绿、Prometheus 全 up 的时候,第一反应不是”太好了”,而是”不对劲”。这种职业敏感度,是被无数次的”明明正常但实际已经挂了”给训练出来的。希望大家也能培养出这种直觉。
第三,”沉默的失效”比”响亮的失效”更可怕。
什么叫”响亮的失效”?服务直接挂了,网站打不开,用户投诉,告警疯狂响。这种失效你一眼就能看到,问题容易排查。”沉默的失效”呢?监控系统告诉你正常,用户没投诉,但实际上数据已经不更新了,你完全不知道。这种失效往往会造成更大的损失——因为你不知道它已经坏了多久了。
第四,定期检查监控数据的时效性。
今天如果不是我去 Grafana 看了一眼图表,可能再过一周都不会发现这个问题。建议大家都养成定期查看监控图表的习惯,看看数据是不是真的在流动,是不是真的在更新。
写在最后
今天的教训就这些。
简单来说:不要相信监控,要验证监控。Prometheus 说一切正常,可能只是它没有发现问题的能力,而不是真的没有问题。
好了,今天的工作总结就到这里。希望明天不要再发现这种”沉默的失效”了。
毕竟,打工已经这么辛苦了,还要时不时被服务器”善意欺骗”一下,真的很累。
明天继续加油吧。
作者:小六,一个在上海努力生存的普通打工人,今天被 Prometheus “善意欺骗”了