故障自愈实战:系统挂了自动修,不用半夜爬起来

去年一个客户,半夜三点被报警吵醒。数据库连接池满了,重启应用就好了。第二天查日志,发现是某个定时任务忘了关连接。改代码、发版,折腾了两天。
他问我:“这种问题能不能自动处理?以后不用半夜爬起来?”
我问他:“重启应用会丢数据吗?”
“不会,无状态。”
“那为什么不让系统自己重启?”
他愣了一下:“没想过。”
这是很多运维团队的思维定势:报警了,人工修。但人工能做的事,脚本也能做。
今天聊聊故障自愈。不是那种“自动化很重要”的入门课,而是帮你理清楚:哪些故障可以自愈?怎么设计自愈规则?怎么防止过度自愈掩盖问题?
01 哪些故障适合自愈
不是所有故障都能自动修。判断标准有三条:
第一,有明确的判定条件。比如“连续3次健康检查失败”或“错误率超过5%”。能说清楚的规则才能写成代码。
第二,恢复动作可脚本化。重启、摘流量、切备、扩容、回滚,这些操作都可以自动化。数据修复、代码bug这类不行。
第三,恢复代价可接受。重启会断连接吗?切流量会丢数据吗?如果代价太大,还是人工处理。
那家客户的数据库连接池问题,判定条件明确(连接池满),恢复动作可脚本化(重启应用),恢复代价可接受(无状态应用)。非常适合自愈。
02 常见的自愈模式
模式一:自动重启
适用:无状态应用、内存泄漏、死锁。
实现:K8s的livenessProbe就是最简单的自愈。检测失败自动重启Pod。
模式二:自动摘流
适用:单点故障、响应变慢。
实现:负载均衡健康检查。失败自动摘掉节点,恢复后自动加回。
模式三:自动切备
适用:主库故障、主可用区故障。
实现:数据库自动切换、DNS自动切换、多AZ负载均衡。
模式四:自动扩容
适用:流量突增、资源不足。
实现:弹性伸缩规则,CPU高了加机器。
模式五:自动回滚
适用:新版本发布出问题。
实现:监控错误率,超过阈值自动触发回滚。
那家客户后来给应用加了livenessProbe:检测/health接口,如果连续3次失败就重启Pod。从此半夜没再被连接池问题吵醒过。
03 自愈规则设计:不要一刀切
自愈规则不是“出了问题就修”。要考虑频率、时机、影响面。
冷却时间:同一个实例,1小时内不要重复自愈。如果连续重启3次还是失败,说明自愈解决不了问题,需要人工介入。这就是“熔断”。
时间窗口:凌晨可以激进一些(没用户),白天要保守(避免误操作)。
影响面控制:先修一个实例观察效果,不要同时修所有实例。
确认机制:高危操作(如切主库)建议加人工确认。低危操作(如重启无状态Pod)可以全自动。
那家客户设了规则:凌晨2点到6点,自动重启;白天只告警不自动重启。连续重启3次后熔断,发告警等人工介入。
04 恢复验证:自愈不是一锤子买卖
自愈不是“执行完动作就完事”。要验证是否真的恢复了。
验证方法:
重新执行健康检查,确认通过
采样业务请求,确认返回正常
检查关键指标(错误率、延迟),确认恢复正常
验证超时:给恢复动作设定时间预算。比如重启后30秒内要恢复健康,否则认为失败,触发熔断或升级。
那家客户在livenessProbe配置里设了failureThreshold: 3,periodSeconds: 10。Pod重启后30秒内必须通过健康检查,否则K8s认为恢复失败,继续按重启策略处理。
05 自愈的边界:知道什么时候交给人
自愈不是万能。有些故障不适合自动修,硬要自动修可能更糟。
不适合自愈的场景:
数据损坏:自动恢复可能覆盖更多数据
配置错误:自动重启解决不了,因为配置还是错的
依赖故障:下游挂了,你重启自己没用
安全事件:需要人工溯源,不能自动清理痕迹
如何设计边界:
自愈只处理明确、可逆的操作
设置熔断阈值,连续失败N次就停,转人工
所有自愈操作记录审计日志
那家客户把自愈范围限定在“无状态应用重启”和“自动扩容”,数据库切换等高危操作仍然走审批流程。
06 一个真实案例:自动清理磁盘,无人值守
一个客户,日志磁盘经常写满,半夜报警,运维爬起来删日志。
我们帮他设计了自愈规则:
监控磁盘使用率,超过85%触发
自动执行
find /var/log -type f -mtime +7 -delete,删除7天前的日志执行后重新检查磁盘使用率
如果降到80%以下,自愈成功,记录日志
如果仍然高于85%,说明日志写太快,触发告警人工介入
半年后,运维负责人说:“半年没因为磁盘问题半夜起来过。”
写在最后
故障自愈的目标不是消灭人工,是把人从重复劳动里解放出来。
那家客户的运维负责人后来总结:“半夜被吵醒的,99%是重复故障。能写脚本的,别让人扛。”
自愈不是替换人,是让人去做更有价值的事:修那些自动修不了的bug,优化那些反复出问题的架构。
你的系统里,还有哪些故障是半夜爬起来重复修的?写个脚本,让它自己修。