贴吧式
自愈边界之争:哪些故障该交给自动重启,哪些必须留给人?
帖子正文与楼层回复。
楼主 沈星河-186
运维SRE自愈Kuberneteson-call
背景
做了 15 年运维,从 2012 年写 crontab 脚本自动拉起进程,到今天在 K8s 里配 liveness 探针 + 自动驱逐重启,"自愈"这个词我们喊了十几年。但每次事故复盘,绕不开一个问题:这条自愈链路,到底是救了我们,还是把故障放大了?
我印象最深的一次:2019 年,一个 4 副本的支付服务,下游依赖的 Redis 集群主从切换,导致 4 个副本在 90 秒内连续被 OOM kill,K8s 自动拉起后继续 OOM,反复循环了 6 轮。最后不是自愈救了我们,是我们手动把副本数缩到 1、把流量切走才停下来的。如果那天 on-call 睡着了,这 6 轮循环会把下游 Redis 也拖死。
常见的三种做法
我观察下来,团队大致分三派:
- 全量自动派:所有非 P0 故障都交给自愈,人只处理 P0。逻辑是"人响应慢、状态差,凌晨 3 点的判断力约等于零"。
- 分级派:按故障类型划边界——OOM kill、进程崩溃可以自动重启;数据库慢查询、连接池耗尽、网络抖动必须人介入。
- 保守派:生产环境一律不自动重启,宁可多叫醒人。逻辑是"误杀的代价远大于多等 5 分钟"。
我的倾向
我站在分级派,但想强调一个被忽略的细节:边界不是按"故障类型"划的,是按"故障的可逆性 + 爆炸半径"划的。
具体标准我用了三年,分享出来大家讨论:
- 可逆 + 爆炸半径小(单副本 OOM)→ 自动重启,最多重试 3 次,第 4 次必须叫人;
- 可逆 + 爆炸半径大(全副本同时异常、数据库连接打满)→ 不自动重启,先告警等人确认;
- 不可逆(数据写坏、配置推错)→ 永远不自动回滚,必须人确认。
但我不确定这个边界在多服务联动场景下还成立不成立。比如服务 A 重启后请求涌向服务 B,B 本来只是 GC 慢,被这波流量打挂了——这种"自愈引发的连锁反应",怎么在规则层面防住?
想听大家聊
- 你们团队现在"自动重启"的边界是怎么定的?是按故障类型、按服务等级,还是干脆全量自动?
- 有没有"自愈反而放大故障"的真实案例?当时的根因是什么?
- 你们怎么决定"重试 N 次后叫人"的 N 是多少?拍脑袋还是有数据支撑?
- 一个比较刁钻的问题:如果 on-call 5 分钟没响应,系统该不该跳过人直接自愈? 这等于把"人"降级成了"延迟确认",你们接受吗?
期待不同规模、不同行业的同学来聊聊。数字越具体越好,"我们大概有几次"这种回答我没法消化,哈哈。
赞 0 · 收藏 0 · 楼层 1
楼层
补充一个工程细节:「重试 N 次后叫人」的 N 不应该拍脑袋,应该从「业务 SLA」反推。具体做法:1) 先定业务 SLA(比如「订单履约 P99 < 5s」);2) 测出平均恢复时间 T(比如 OOM kill 后 K8s 拉起 + 预热 = 3s);3) N = floor(SLA / T) - 1(留一次余量给「叫人」的响应时间);4) 前 N 次用指数退避(1s/5s/30s),第 N+1 次触发熔断,不再重试,直接告警。关键细节:重试之间要做「健康检查」(比如调 /health 接口确认服务就绪),不是盲目 sleep 后重试——盲目重试在「服务还在启动中」的场景下会把流量打到半就绪的实例上,反而放大故障。