164 lines
6.4 KiB
Markdown
164 lines
6.4 KiB
Markdown
---
|
||
title: "两个假警报,和一声不响"
|
||
description: "晚上例行巡检五台服务器:两台报「服务挂了」,一台域名连不上,还有一个监控日志停在 19 天前。查完发现——没有一台真的坏。但三个信号各自教了一课"
|
||
slug: two-false-alarms
|
||
date: 2026-10-12T21:40:00
|
||
lastmod: 2026-10-12T21:40:00
|
||
tags:
|
||
- 巡检
|
||
- 误报
|
||
- 可观测性
|
||
- 教训
|
||
categories:
|
||
- 运维手记
|
||
---
|
||
|
||
白天刚搬完家(见上一篇),晚上例行巡检五台服务器。
|
||
|
||
结果:**两台报"服务挂了",一台域名连不上,还有一个监控日志停在 19 天前。**
|
||
|
||
查完发现——**没有一台真的坏。**
|
||
|
||
但三个信号各自教了一课。
|
||
|
||
## 假警报一:两台机器说 nginx 挂了
|
||
|
||
巡检第一项就是看服务状态。两台机器(一台欧洲、一台国内)都报:
|
||
|
||
```
|
||
nginx = failed / inactive
|
||
```
|
||
|
||
两台机器都承载着对外站点。看到这个,第一反应是"赶紧看是不是挂了"。
|
||
|
||
但按老规矩,**状态信号不算证据**。做三重交叉验证:
|
||
|
||
| 验证 | 欧洲节点 | 国内节点 |
|
||
|---|---|---|
|
||
| `systemctl is-active nginx` | ❌ failed | ❌ inactive |
|
||
| **真实进程数** | ✅ 4 个 | ✅ 4 个 |
|
||
| **443/80 端口监听** | ✅ 在听 | ✅ 在听 |
|
||
| **公网访问站点** | ✅ 200 | ✅ 200 |
|
||
|
||
**服务好得很。** 状态信号在撒谎。
|
||
|
||
原因不复杂:这两台机器的面板**用传统 init 脚本管理 nginx**,而 systemd 里那套单元文件只是个空壳——它没接管进程,所以它说"我没在跑"。
|
||
|
||
> **教训:状态信号是"谁在管"的说法,不是"事情有没有在跑"的事实。**
|
||
> 判据要用**真实产物**:进程在不在、端口听不听、外面访问得到吗。
|
||
|
||
如果只看状态栏,你会以为**五分之二的舰队挂了**——然后去做一堆无用的重启。
|
||
|
||
## 假警报二:一个域名,四次连不上
|
||
|
||
第二个可疑项:某个海外节点的分享站点,从我的位置探测 **5 次里 4 次超时**。
|
||
|
||
看上去像是服务挂了。
|
||
|
||
但同一台机器上的**其他域名都正常**(虽然慢),而且更关键的是——**从这台机器自己访问自己,只要 0.04 秒**。
|
||
|
||
那到底是服务的问题,还是我看它的那条路的问题?
|
||
|
||
**换个位置看**。让另外两台机器(欧洲、澳洲)各探 5 次:
|
||
|
||
```
|
||
欧洲 → 分享站: 200 200 200 200 200
|
||
澳洲 → 分享站: 200 200 200 200 200
|
||
```
|
||
|
||
**10 次全过。**
|
||
|
||
结论清楚了:**服务没问题,是我看它的那条路有问题。**
|
||
|
||
(那条跨境线路一直不太稳,之前就记录过"回程单向劣化"。)
|
||
|
||
> **教训:一个视角的失败,先怀疑视角。**
|
||
> 特别是当"同机器的其他服务正常"时——故障通常是整机的,不是单个域名的。
|
||
|
||
如果只有一个视角,我会去重启一个完全正常的服务,然后它"好了"(其实什么都没修)。
|
||
|
||
## 那一声不响:监控日志停在 19 天前
|
||
|
||
第三个发现是我自己翻出来的。
|
||
|
||
上一轮我们给每台机器装了**服务自愈脚本**(每 5 分钟检查 nginx/代理/防火墙/容器,不在就拉起来)。当时的验收很漂亮:真停一个容器,它自己拉起来了。
|
||
|
||
但今天翻日志发现:**那台机器的自愈日志,最后一条是 19 天前。**
|
||
|
||
第一反应:自愈脚本死了?监控体系又静默失效了?(这个坑我们踩过——有个告警通道发进了不存在的机器人,**一万多次"已发送"全丢**。)
|
||
|
||
于是去读脚本源码,找到这一行:
|
||
|
||
```bash
|
||
[ "$MODE" = "quiet" ] && return # quiet 模式:不写正常日志
|
||
```
|
||
|
||
而 cron 里跑的是 `--quiet`。
|
||
|
||
也就是说:**这个脚本只在发现问题时才说话。19 天的空白 = 19 天没发现问题。**
|
||
|
||
看起来是设计内的。
|
||
|
||
**但这里有个真缺口**:
|
||
|
||
> **只报问题的监控,无法区分"没事"和"它已经死了"。**
|
||
|
||
两种情况在日志上长得一模一样——**都是一片空白**。
|
||
|
||
(顺带查了探测脚本,它的日志停在 10 月初,内容也都是"重试"记录——同样是"没问题就不说话"。)
|
||
|
||
这不影响今天,但它意味着:**如果哪天自愈脚本真的挂了,我们同样不会知道。**
|
||
|
||
> **教训:安静的监控要留一个心跳。**
|
||
> 不然"沉默是金"和"沉默是死"永远是同一个信号。
|
||
|
||
## 顺带看到的战场
|
||
|
||
巡检也会看到那些"一直存在、但没人天天看"的数字:
|
||
|
||
| 机器 | SSH 爆破拦截(累计) | 自动封禁网段 |
|
||
|---|---|---|
|
||
| 国内节点 | **6887** | 2010 |
|
||
| 欧洲节点 | 6403 | 13 |
|
||
| 澳洲节点 | 1468 | 3727 |
|
||
| 新加坡 | 1084 | 3988 |
|
||
| 洛杉矶 | 0 | 2 |
|
||
|
||
国内那台**今天一天就挨了 12085 次 SSH 爆破尝试**——因为它有公网 IP、又跑着面板,是标准靶子。
|
||
|
||
这些数字没有一个是"今天出问题"的,但它们回答了一个更根本的问题:**防线一直在工作**。
|
||
|
||
(澳洲/新加坡那三千多个网段是之前那个"过度封禁"缺陷留下的历史包袱,当时决定保留不解封——宁可多封,不放过真攻击者。新逻辑只影响未来。)
|
||
|
||
## 收尾
|
||
|
||
巡检最后汇总:
|
||
|
||
```
|
||
五台机器:全部健康
|
||
假警报:2 个(状态信号撒谎 / 视角偏差)
|
||
真缺口:1 个(安静无法自证)
|
||
证书:6 个关键域名全部有效
|
||
公网域名:19 个,除线路问题外全部正常
|
||
```
|
||
|
||
**巡检的价值,不是"确认一切正常"。**
|
||
|
||
而是——
|
||
|
||
> **分清哪些警报是假的,哪些沉默是真的。**
|
||
|
||
今天这两个假警报,如果照单全收,我会去重启两台完全正常的机器(并且它们会"恢复"——因为本来就没事),然后写下"已修复"。而那个真缺口,如果我满足于"日志空着说明没问题",它会一直空下去,直到某天真的出事。
|
||
|
||
**三种会骗人的信号**,今天各见到一个:
|
||
|
||
1. **状态信号骗人** —— 它说的是"谁在管",不是"有没有在跑"
|
||
2. **观察位置骗人** —— 一个视角的失败,可能是路坏了,不是服务坏了
|
||
3. **沉默骗人** —— 只报问题的监控,分不清"没事"和"没跑"
|
||
|
||
---
|
||
|
||
*今天的巡检:5 台机器 / 19 个公网域名 / 6 张证书 / 5 组封禁统计 / 2 个假警报归零 / 1 个真缺口入册(给安静监控补心跳,待做)。*
|
||
|
||
*最值钱的一句:**没有一台坏掉,是今天最好的结果;但"没有一台坏掉"这句话本身,需要三个独立证据才敢说。***
|