故障处理协同:一个群变成一条流程

运维值班群有二十三个人,告警机器人也在里面。上线初期群里一天两百多条消息,告警、闲聊、外卖红包混在一起。有天晚上八点一条数据库连接数告警发出来,被人当成噪音略过,两个小时后业务那边打电话过来,我们才知道主库已经撑了九十分钟。

那次复盘没人推责任,问题很清楚:群能传递消息,不能传递状态。谁在看、谁在处理、处理到哪一步,全靠人打一句"在看"。后来我把故障处理做成一条流程,群只留通知。这篇文章写清楚分级怎么定、升级规则怎么写、状态怎么收敛。

一、群里的故障为什么会拖

1.1 一条告警两小时没人认领

事后翻聊天记录,那条告警发出的前五分钟,群里正在讨论一次发布,消息刷了四十多条,告警被顶到上面。有人看到了,以为是发布引起的抖动,打算等发布完再看。

九十分钟里没有任何人说自己接手。三个值班的人各自以为别人在看,这种"责任分散"在群里很常见,人越多越容易出现。

1.2 群消息的三个缺陷

群消息缺三样东西。缺归属:一条消息发出来,没有"负责人"这个字段,只能说"我来看",而说话的人可能正在外面。缺时间:消息太多,什么时候发的、过了多久,要往上翻才知道。

缺状态:处理到一半的故障和已经恢复的故障,在群里长得一样,都是一句"好了没"。三样都缺,管理者只能靠问,问一次全组被打断一次。

还有一种情况更麻烦:故障处理完,经验留在聊天记录里。三个月后再出同类问题,没人记得当时改的是哪个参数。群消息会过期,翻起来也难,这不是人的记性问题,是载体不对。

1.3 流程要解决的是谁在做什么

流程不是把群搬到系统里,那只是换个地方刷屏。流程要解决的是三件事:这条故障归谁、现在到哪一步、下一步该谁动。

把这三件事变成字段,人就不用互相问。群里只剩下结果通知,刷屏问题自然消掉。我给自己定的验收口径是:任何一个故障,点开能看到负责人和状态,不用问人。

顺带说一个副作用。责任一旦显性,值班的人开始主动说"我接了",这句话在群里出现,比任何流程文档都实在。以前不说是因为说了就等于背锅,现在说了是系统记一笔工,性质不一样。

二、事件分级与升级规则

2.1 分级看影响面,不看情绪

分级容易走偏。有人报障时语气急,就被定成高等级;语气平,就被定成低等级。同一类问题两次定级不一样,值班的人也无从判断该多快响应。

我们把分级改成按影响面算,两个因子:受影响的范围是核心链路还是单个模块,受影响的用户量级。两个因子组合出三个等级,规则固定,谁填都一样。填单的人只能选范围,等级由系统算。

2.2 升级的触发条件

升级不是"领导觉得该升级了",得有触发条件。我们用了三类:超时未认领、认领后长时间无进展、影响面扩大。

三类条件里,超时类能自动化,后面两类需要人判断。自动化的部分交给定时任务,每分钟扫一遍未关闭的事件,符合条件就往上一级推一条。人工的部分留一个按钮,值班的人觉得压不住可以手动升。

2.3 规则写成可执行的表

下面的代码是升级判定的核心。规则表按等级配好响应时限和通知链,nextTarget 判断当前该通知谁,tick 每分钟跑一遍。没有写成一堆 if,是因为规则会变,改成表之后调整只动数据。

const MATRIX = [
  { level: "P1", hit: e => e.scope === "core" || e.users >= 500, ack: 5,  chain: ["oncall", "lead", "duty"] },
  { level: "P2", hit: e => e.scope === "module" || e.users >= 50, ack: 15, chain: ["oncall", "lead"] },
  { level: "P3", hit: () => true, ack: 60, chain: ["oncall"] },
];

const ruleOf = e => MATRIX.find(r => r.hit(e));

function nextTarget(e, now) {
  const rule = ruleOf(e);
  if (!rule || e.state === "closed") return null;

  if (e.state === "fired") {
    const waited = (now - e.firedAt) / 60000;
    if (waited >= rule.ack) {
      return { to: rule.chain[0], text: `${e.id} 触发 ${rule.level},${rule.ack} 分钟未认领` };
    }
    return null;
  }

  if (e.state === "acked") {
    const hold = (now - e.ackedAt) / 60000;
    const step = Math.floor(hold / rule.ack);
    if (step >= 1 && step < rule.chain.length) {
      return { to: rule.chain[step], text: `${e.id} 处理中超过 ${step * rule.ack} 分钟` };
    }
  }
  return null;
}

function tick(events, now, send) {
  for (const e of events) {
    const t = nextTarget(e, now);
    if (t) send(t.to, t.text);
  }
}

代码里有个细节:step 从 1 开始算,因为第 0 级是认领之前的通知,已经在 fired 分支里处理过了。两者用同一个 ack 做步长,实际跑下来节奏正好,高等级故障五分钟一档,低等级一小时一档。

2.4 升级不是叫人越多越好

刚开始我把通知链配得很长,P1 一次推七个人。结果是高等级故障一来,七个人同时进群问"什么情况",反而干扰处理。

后来改成链式:先推值班,超时推组长,再超时推部门负责人。同一时刻只有一个人在动,责任清楚。七个人同时收到消息的场面看着热闹,实际谁都不动。

三、把群里的动作搬到流程里

3.1 三个状态就够

事件状态我们只留三个:待认领、处理中、已关闭。中途想加"已定位""待验证"之类的细分,被否了,因为状态一多,填的人就开始选错。

细分信息放在处理记录里,不强求状态表达。状态管的是责任流转,记录管的是过程。两件事分开,系统反而好用。

3.2 时间戳比描述重要

每条事件记五个时间:发生、通知、认领、恢复、关闭。这五个时间点能算出四个指标:响应时长、处理时长、恢复时长、确认时长。

描述可以写得含糊,时间戳含糊不了。有次讨论响应慢,把上个月的五个时间拉出来看,发现慢在"恢复"到"关闭"这一段,业务侧确认拖了两天。方向一下就清楚了。

3.3 与群的衔接只推关键节点

群没有废掉,只做通知出口。推的消息有三类:新事件、升级、关闭。每类一条,带编号和链接,点开进系统看详情。

处理过程中的讨论还在群里,但结论要回到系统里写一句"处理记录"。不要求写长,一两句就行。这样群里的信息可以丢,系统里的不会。

3.4 事件与变更挂在同一条时间线上

故障有一半和变更有关。我们把变更记录也接进来,事件详情里能看到前后两小时内有没有发布、有没有改配置。

这个关联省了很多猜测。有一次接口超时,处理的人一开始在查数据库,看到时间线上四十分钟前有一次限流配置调整,直接去看那个改动,十分钟定位。没有这条时间线,同样的排查要走两小时。

四、跑了半年的调整

4.1 升级太频繁会失效

头两个月升级次数太多,一周十几次,值班的人开始麻木,收到升级消息只当背景音。查下来是两个原因:响应时限配得太紧,以及大量重复告警各自成单。

调整办法是把同源告警合并成一单,五分钟内的同类告警归到同一事件里,只在首次触发通知。改完之后一周升级三四次,每次都是真的需要人动。

4.2 误报怎么消化

误报不能靠忍。我们给每个事件加了一个"误报"标记,关闭时选。每月统计一次误报率,按告警规则分组看,误报率高的规则直接下线或者调阈值。

有个磁盘告警规则误报率到六成,原因是它监控的是缓存目录。改监控路径之后降到一成以下。规则不清理,值班的人就会练出"看到也不动"的习惯,这比漏报更难纠正。

4.3 复盘要能落到改动

复盘不写长文,一张表三列:发生了什么、哪个环节慢了、改什么。第三列必须落到具体动作,比如"把超时时间从十五分钟改成十分钟",不能写"加强监控"。

半年下来这张表攒了四十多条改动,其中三十多条已经上线。复盘的价值不在文档,在于改完之后同类故障的响应时间有没有下来。

我们现在的做法是复盘完两周回看一次,看改动有没有真的生效。有两次改完忘了上线,表上写着"已改",系统里还是旧参数。回看这一步不难做,但少了它,复盘就是写字。

常见问题

问:小团队有必要做这么一套流程吗?

答:三个人的团队可以不建系统,但分级和升级时限这两件事得有,写在纸上也行。关键不是工具,是有没有人负责。人少的时候责任分散更隐蔽,两个人互相等着对方动手,一样会拖。

问:升级通知发到群里还是私聊?

答:私聊或专门的通知通道。发群里会被刷过去,尤其在有告警机器人的群里。私聊的好处是明确指向一个人,对方不回就没有借口。升级到负责人那一级时,可以同时抄送群,让其他人知道当前状态。

问:值班的人休假了,告警还会升级给他吗?

答:会,所以要有值班表。升级逻辑读当天的值班人,不读固定的人。换班在值班表里改,升级链自动跟着变。这一层不做,休假的人手机响一晚上,返岗就想辞职。

问:事件合并会不会把不同的故障合成一单?

答:合并要看来源标识,不能只看时间。同一条告警规则、同一个对象、五分钟内重复,才合并。不同规则即使同时触发也不合并。合并规则放宽,会把两个独立故障压成一单,处理的人容易只解掉一个就关单。

posted @ 2026-10-23 17:34  离线漫游中  阅读(9)  评论(0)    收藏  举报