技术指南
VPS 监控闭环:从外部探测到告警恢复
从外部探测、内部信号、持续告警到恢复验证,建立能发现用户症状并保留行动证据的 VPS 监控闭环。
监控不是把一台 VPS 接进仪表盘,而是建立一条可验证的处置闭环:从用户视角发现异常,经过持续条件和通知路由送到能行动的人,再用独立证据确认恢复。主机指标、日志和面板用于解释原因;它们不能代替真实请求,也不能证明告警通道本身仍然可用。
先定义什么叫真正成功
把关键路径写成机器可判断的条件。一个公开 HTTP 服务通常至少包含 DNS 可解析、TCP/TLS 可建立、响应在时限内、状态码符合预期、正文或 JSON 字段正确。只看 `200` 会漏掉错误模板、空页面和被代理缓存的旧结果;只看 `ping` 则连应用协议都没有经过。
| 信号 | 回答的问题 | 不应单独推出的结论 |
|---|---|---|
| 外部探针 | 用户能否从外部完成关键请求? | 不能解释根因,也不代表所有地区都正常 |
| 应用指标 | 请求量、错误率和延迟怎样变化? | 采集成功不等于入口可达 |
| 主机指标 | CPU、内存、磁盘、连接和 I/O 是否接近容量? | 单次高值不等于用户受损 |
| 日志与追踪 | 哪条请求、依赖或部署发生了什么? | 没有日志不等于没有故障 |
| 任务心跳 | 批处理最近是否完整成功? | 进程启动不等于产物可恢复 |
把探针放到另一故障域
监控端与业务端共用同一 VPS、DNS、网络出口、账号或通知平台时,一次故障可能同时让服务和证据消失。小规模部署不必追求复杂集群,但要明确哪些失效会一起发生,并至少为最关键路径保留独立观察点。
| 共同故障 | 会留下的盲区 | 最小补偿 |
|---|---|---|
| 探针与服务同机 | 主机或网络失联时无法上报 | 从另一主机或托管探针发起外部请求 |
| 监控与业务共用 DNS | 解析故障会同时隐藏状态入口 | 独立域名/解析与直接的备用联系路径 |
| 只有一个通知渠道 | 平台、Token 或静音配置失效无人知晓 | 定期端到端测试并保留第二路严重告警 |
| 状态页与生产同域 | 事故时公开说明也不可达 | 将公开状态面与内部监控分离 |
让 HTTP 200 也能判定失败
探针要有连接和总时限、明确的状态码、精确但稳定的内容断言,并且不能携带真实用户凭据。健康接口只返回最少信息,不泄露版本、主机名、堆栈或依赖 Secret;关键事务若必须登录,应使用权限受限的专用测试身份。
#!/usr/bin/env bash
set -u
url=${1:?usage: probe.sh URL EXPECTED_BODY}
expected=${2:?usage: probe.sh URL EXPECTED_BODY}
work=$(mktemp -d)
trap 'rm -r -- "$work"' EXIT
if ! status=$(curl --silent --show-error --output "$work/body" --write-out '%{http_code}' \
--connect-timeout 1 --max-time 2 "$url"); then
printf 'transport_error\n' >&2
exit 20
fi
[ "$status" = 200 ] || { printf 'http_status=%s\n' "$status" >&2; exit 21; }
grep -Fqx -- "$expected" "$work/body" || { printf 'content_mismatch\n' >&2; exit 22; }
printf 'probe_ok http_status=200\n'退出码要区分传输错误、协议状态和内容错误,通知中只带目标别名、UTC 时间、状态和运行手册链接。查询字符串、命令行和截图都会传播凭据;Push Monitor 的 token 本身就是 URL 路径凭据,应按 Secret 保存、脱敏和轮换。
用持续条件过滤短抖动
采样间隔、超时、连续失败次数和告警持续时间必须从可接受的发现时间与误报成本反推,不能承诺固定的“一分钟通知”。Prometheus 的 `for` 会让条件持续满足后才进入 firing;`keep_firing_for` 可以在条件短暂消失后保持一段时间,减少假恢复与抖动。两者都要结合评估间隔、网络重试和业务 SLO 记录实际最坏发现时间。
- 紧急页面只覆盖正在发生或即将发生、用户可见且需要人工行动的症状。
- 容量、证书临近到期和备份陈旧可进入工单或较低级别通知,不必全部叫醒值班人。
- 缺失数据必须有明确语义:探针没样本可能是监控断了,不应自动当成服务健康。
- 恢复通知要等关键路径再次通过,并保留故障开始、确认和恢复的 UTC 时间。
资源指标用于解释,不替代症状
CPU、内存、磁盘、inode、I/O 等待和连接数应按业务基线、容量上限和持续时间解释。固定的 CPU 或内存百分比既忽略突发型实例,也忽略缓存和工作集;单个瞬时尖峰通常更适合留在图表。面向用户的服务先看延迟、流量、错误和饱和度,再用主机及依赖指标缩小原因。
任务心跳只在完整成功后发送
备份、证书续期和定时同步属于“最近是否成功”的问题。心跳应在命令退出成功、产物存在且最小校验完成后才发送;阈值通常至少容纳计划间隔、正常运行时间和一次可接受重试。若一次失败就会造成用户损害,应提高运行频率或减少单次任务的重要性,而不是只把阈值调得更敏感。
- 备份:快照创建成功后检查仓库并按计划做恢复演练,不能只监控脚本退出码。
- 证书:同时监控到期时间和真实 TLS 握手,避免只看到本地文件已更新。
- 同步:验证目标端的时间戳、数量或校验值,再提交成功心跳。
- 心跳 URL 中的 token 不进入日志、进程参数、聊天和截图;失败路径绝不发送成功。
把检测与通知路由分开
告警规则负责判断条件,通知层负责去重、分组、路由、静音和抑制。Alertmanager 的 grouping 可以把同一事故的多个实例压成一条通知,inhibition 可以在上游整体故障时抑制下游噪声,silence 只是在限定时间内停止通知;静音不是修复,也不应抹掉仍在 firing 的证据。
| 状态 | 处理动作 | 退出条件 |
|---|---|---|
| pending | 观察条件是否持续,核对部署或维护窗口 | 条件消失或达到 firing 持续时间 |
| firing | 确认用户影响、执行运行手册、记录负责人 | 独立探针恢复并完成验证 |
| silenced | 记录匹配范围、理由、所有者和到期时间 | 到期后规则仍须重新评估 |
| resolved | 确认真实事务、通知恢复并补齐时间线 | 证据表明关键路径稳定,而非单个样本变绿 |
监控系统也要被监控
采集器、规则引擎、通知器和外部探针都可能失效。保留一个跨越探针、规则、路由和接收端的周期性测试,并监控最后成功时间、规则评估错误、通知失败与队列积压。内部白盒指标再丰富,也要有独立黑盒检查作为监控链路完全失效时的后备。
告警里带够行动证据
- 稳定的服务与环境标签,不用会爆炸增长的请求 ID 作为指标 label。
- 当前值、持续时间、最近变更和 UTC 时间窗。
- 用户症状入口、关联面板、日志查询和最短运行手册。
- 负责人、严重级别、静音/维护状态和明确的升级路径。
- 恢复时使用同一事件标识关联开始、确认、缓解与结束。
本次隔离演练验证了什么
本批在 `127.0.0.1:18084` 启动一次性 Python HTTP fixture,未接触生产服务、通知平台或真实凭据。探针对正确 JSON 返回 0;HTTP 200 但正文错误返回 22;503 返回 21;超过两秒的响应和关闭端口分别由 curl 28 与 7 触发传输错误并返回 20。重启 fixture 后探针恢复为 0,退出后 `ss` 确认端口未监听。
这次演练只证明探针的协议、内容、时限、故障分类和恢复路径。它不能证明某个外部地区可达,也不能证明真实通知路由、值班响应或备份恢复有效;这些必须在各自环境用不含 Secret 的计划演练补齐。
上线前的闭环验收
- 关键路径有可判定的成功条件,HTTP 200 错误内容也会失败。
- 至少一个探针位于业务主机之外,并记录共同故障域。
- 发现时间、持续条件、缺失数据和恢复条件均有明确语义。
- 页面只针对可行动的用户症状,资源阈值主要用于容量和诊断。
- 任务心跳在完整成功与最小校验后发送,token 按 Secret 处理。
- 通知路由完成测试,分组、抑制、静音和升级责任可复核。
- 状态页与内部监控数据分层,监控链路自身有独立检查。
- 故障与恢复演练留下 UTC 时间、结果和清理证据。