只在状态变化时告警:用 cron + 状态文件搭一套不吵人的轻量监控

举报
yd_276135645 发表于 2026/10/23 10:32:43 2026/10/23
【摘要】 探针只做判定、状态落盘、只在翻转时通知:用 cron 和一个状态文件做一套不吵人的轻量监控,含原子写、退出码、HTTP 状态码三个坑。

凌晨三点服务挂了,你早上八点才发现。不是你收不到报警,而是过去一周每五分钟就有一条“一切正常”的推送,那个群早就被你静音了。

监控最难的部分从来不是采集指标,而是在不该说话的时候闭嘴。这篇文章记录一套只用 cron 和一个状态文件就能落地的做法:探针只做判定,状态写盘,只在状态翻转时输出。没有 Prometheus,没有告警平台,一台最低配的服务器就够。

一、先把“探针”和“告警”拆开

很多脚本的错误在于把两件事写在一起:检查、发现问题、顺手发消息。结果是脚本既是探针又是通知器,换一次通知渠道就要动检查逻辑,而且永远回答不了“这东西到底挂了多久”。

拆成三层就清爽了:

  1. 探针:只输出一个状态字符串,例如 healthy / unauthorized / unreachable;
  2. 状态文件:记录上一次的状态和时间戳,用来去重、算持续时长;
  3. 通知器:只在状态变化时,把“新状态 + 上一条状态持续了多久”发出去。

二、最小可用实现

探针脚本 probe.sh,只做判定,退出码永远是 0:

#!/usr/bin/env bash
set -u
DIR=/var/lib/probe
mkdir -p "$DIR"

code=$(curl -s -o /tmp/body -w '%{http_code}' \
       --max-time 8 https://127.0.0.1:5000/v1/api/health || true)

case "$code" in
  200)    state=healthy ;;
  401|403) state="unauthorized" ;;   # 鉴权接口:401 就是“没登录”
  000|"") state="unreachable" ;;
  *)      state="http-$code" ;;
esac

last=$(cat "$DIR/last" 2>/dev/null || echo unknown)

if [ "$state" != "$last" ]; then
  printf '%s' "$state" > "$DIR/last.tmp" && mv "$DIR/last.tmp" "$DIR/last"
  printf '%s' "$(date +%s)" > "$DIR/since"
  printf '%s  %s -> %s\n' "$(date '+%F %T')" "$last" "$state" >> "$DIR/transitions.log"
  echo "$state"     # 只有这一行会变成手机上的推送
fi

有三个细节值得单独说:

1. 状态文件要原子写。 用 printf > tmp && mv,不要直接覆盖。读文件的那一瞬间如果正好写到一半,读到空内容会让下一次判定误以为“状态变了”,凭空制造一条假告警。

2. 退出码恒为 0。 大多数调度器把非零退出当成“任务失败”,于是你不仅收到业务告警,还额外收到一条“探针自己挂了”。把判断结果写在 stdout,把“我跑不动了”留给真正的异常路径。

3. HTTP 状态码先于响应体。 401/403 的 body 通常是空的,先当 JSON 解析再判断会得到“解析失败”,一个真实的鉴权故障就这样被伪装成了脚本 bug。先看 %{http_code},只有 200 才值得读 body。

三、接到 cron 上

*/5 * * * * /usr/local/bin/probe.sh >> /var/log/probe.log 2>&1

如果调度器支持“只有输出才通知”的脚本模式(stdout 为空就什么都不发),到这里就结束了:正常时零消息,翻转时一条。

如果不支持,加一层薄包装:把非空的 stdout 转成一次 webhook 调用。包装层不要写任何判断逻辑——判断只有一处,才不会有第二个真相。

四、把“观察”和“自愈”拆成两个任务

线上最危险的动作是“探针判断失败就自动重启、自动重新登录”。判断错的代价可能比故障本身更大:涉及账号鉴权的场景,连续失败重试会直接撞上风控,一次掉线被放大成账号锁定。

所以实际部署里我拆成两个任务:

  • 观察任务:只读状态、只报变化,永远不执行修复。它的真正价值是测量——某个会话平均能活多久、失败集中在什么时段。这些数据决定了自愈到底值不值得做。
  • 自愈任务:频率更低、动作更保守,一次只尝试一次,失败就停下来等人。

先跑一周观察、攒够数据,再决定要不要上自愈。顺序反过来,你会收获一堆“系统正在自我修复”的推送,以及一个越来越难解释的故障史。

五、边界

它不存历史指标,不做趋势分析,替代不了真正的时序数据库。但它能回答三个最要紧的问题:现在是什么状态、什么时候变的、这个状态持续了多久。对单机、单服务、个人项目来说,这三个问题占了告警价值的九成。

整套东西不到六十行,没有依赖,半年后的你自己还能读懂——这大概是它最大的优点。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。