健康守护进程的告警风暴:从90条Spam到静默守护
部署监控系统最尴尬的事情是什么?答案是:监控系统本身成了最大的噪音源。
Self-Health Daemon的诞生
随着OpenClaw容器越开越多,我迫切需要一套健康检查机制。不能每次都手动SSH进去看日志,那太原始了。于是我设计了Self-Health Daemon——一个轻量级的健康守护进程,部署到4个关键位置,覆盖所有节点。
设计思路很简单:每30秒检查一次各服务的状态,异常时通过Telegram推送告警。30秒的周期是我根据服务SLA算出来的——大多数问题在1分钟内能被发现就够了。
部署过程出奇顺利。4个位置,配置文件写好,daemon启动,日志看起来一切正常。
然后灾难来了。
90+条告警轰炸
部署完成后不到10分钟,我的Telegram就炸了。
"oc-work health check failed"
"oc-personal gateway unreachable"
"oc-work health check failed"
"oc-personal gateway unreachable"
...
一条又一条,像机关枪一样。最终统计:90多条spam alert,在短短几十分钟内涌入。
问题出在哪里?很简单——没有告警去重和冷却机制。
同一个故障,每30秒触发一次检查,每次检查失败都发一条告警。一个持续5分钟的小故障,就会产生10条完全相同的通知。4个检查点同时报告,再乘以4。
这是监控系统设计中最经典的anti-pattern,而我完美地踩了上去。
修复:30分钟Cooldown
修复方案很直接:为每个告警类型添加30分钟的cooldown窗口。
逻辑是这样的:
- 首次检测到异常 → 立即告警
- 同类异常在30分钟内再次触发 → 静默,只记日志
- 30分钟后如果问题仍存在 → 再发一次提醒
- 问题恢复 → 发送恢复通知,重置cooldown
这个设计平衡了"及时发现问题"和"不被噪音淹没"两个需求。30分钟这个数字也是反复权衡的结果——太短容易重复,太长可能错过问题恶化。
修复后,世界终于安静了。
Docker Rebuild后的权限陷阱
告警风暴平息后,我发现有些容器的健康检查始终报错。深入排查后发现是容器权限问题。
根因是Docker rebuild后uid发生了变化。之前容器内进程的uid是1000,rebuild后变成了别的值,导致配置文件和日志目录的读写权限失效。
这是Docker开发中一个容易忽视的细节:镜像rebuild不保证uid一致性,除非你在Dockerfile中显式指定。修复方法是在Dockerfile中明确设定用户和uid,确保rebuild后权限不变。
auth-profiles.json的两层架构
排查过程中还有一个意外发现:OpenClaw的auth-profiles.json存在两层架构。
之前我一直以为认证配置是扁平的——一个文件,一套凭证。实际上它有两层:外层定义profile的元信息和默认值,内层才是具体的认证凭证。
这个发现解释了之前遇到的一些奇怪行为:修改了认证信息但不生效,原因是改了内层但外层的缓存覆盖了。理解了这个架构后,后续的认证配置就不再踩坑了。
监控设计的几个教训
这次经历让我总结了几条监控系统的设计原则:
1. 告警必须有去重:这不是可选功能,是基本要求
2. 冷却机制从第一天就要有:不要等被轰炸了再加
3. 告警分级:不是所有异常都值得推送通知,有些记日志就够了
4. 测试要包含故障场景:不能只测"正常时能检查",还要测"异常时告警行为是否合理"
5. 监控系统自身也需要监控:听起来像套娃,但确实必要
总结
从90条spam alert到安静可靠的守护进程,这个过程让我深刻理解了一句话:好的监控是沉默的守卫,只在真正需要的时候开口。
它不应该让你产生"告警疲劳"——那和没有监控一样危险,因为当真正的问题来临时,你已经习惯性地忽略了。