今天晚上发生了一起线上事故,我是这场事故的主要负责人。经历了两个小时的排查,虽然最终解决了问题,但是也暴露出我心态和能力上的一些不足。趁着这件事情的余波仍在,赶紧记录一下。
快到晚上七点钟的时候,业务方找到我说,有一批会议的邀请短信一直没有发出去,而会议七点钟就要开始了。我一听时间紧迫,赶紧排查。发送邀请短信是由定时任务来完成的,这个定时任务设计的有问题,如果发生异常就会卡住。之前也遇到过这种情况,需要把产生异常的数据干掉,任务才能继续执行下去。因此当我打开定时任务后台,看到执行记录全是失败时,其实并没有多少意外。
意外发生在我打开执行日志的时候,看到里面是工单系统的创建工单接口报的一个错:处理人不能为空。我这时候有点懵,第一感觉是工单系统是不是改东西了,因为我知道我这里没动,之前又一直好好的,所以有这种可能。
虽然工单系统的报错让我感到困惑,但我也清楚当务之急是把短信发出去。于是我到Redis上把异常数据给干掉了(留了备份)。这里需要说明一下Redis的作用,是作为事件的注册器,比如短信渠道的会议邀请就是一个事件,微信渠道的文章邀请可能是另外一个事件。这些事件存储在一个zset里,value是eventId_channelId,score是执行时间(事件有立即执行和定时执行两种方式)。
定时任务每分钟扫描事件注册器,执行所有需要执行的事件。问题随之产生。阻塞的事件一旦被我干掉,所有积压的事件一下子全都执行了。这就导致有些已经结束的会议,这会儿却把邀请短信给用户发出去了。还有可能导致用户一下子接到好几个短信,形成短信轰炸,用户甚至会因此投诉我们。这个后果是非常严重的。
所以,虽然我以最快的速度帮业务方把短信发出去了,但也造成了非预期的结果。到底是功大于过还是过大于功还真不好说。其实在我干掉异常数据之前,我是知道会发生什么的。然而我在权衡之后,却做出了错误的决断。如果我能够不那么鲁莽,也许最后的结果就不是这样。