在做系统的开发过程中,大家都会遇到线上的事故这个问题。即使再牛的工程师也没有办法保证所开发的系统完全没有bug。而且事故的原因也不仅仅是系统bug,可能还有各方面的原因,有软件层面的、有硬件层面的、有网络的等等。
一个高级别的架构师与一般的工程师的主要区别就在于实现业务功能的同时,在系统健壮性、稳定性方面设计的差异。可能当一切正常的时候,普通程序员开发的系统也能够满足业务的场景,但是一旦发生异常的时候,这时候普通程序员与架构师设计的系统的区别就体现出来了。普通程序员设计的系统可能出现一点异常的时候整个系统就无法使用了,高级别的架构师在设计系统的时候会充分考虑各种异常的场景以及降级措施,当系统出现问题的时候保证系统能够正常稳定运行。
线上事故既然不可避免,一旦发生现场事故之后如何进行处理呢?
同样的一个线上的事故,如果处理的方法不一样那么导致的结果也会完全不一样。在没有任何方法论的时候很多人上去同时处理,大家都很积极,各抒己见,争论不休,这种无序的状态反而导致处理问题的效率降低。在处理线上问题过程中要争分夺秒,因为每慢一分钟,线上就多一分钟的损失。
但是如果有一套有效的分工与方法之后,可能分钟级别就可以把线上的事故解决掉,大大提升了解决问题的效率。我们在这方面也吃过很多亏,很多线上的事故,其实并不是很复杂,但是在事故处理过程中组织的不是很好,导致处理问题耗时较长。
经过我们对之前事故的过程不断复盘,总结出一套处理线上事故的方法论,可能还不是很完善,但至少大家思路统一,不完善的地方后续可以继续迭代完善。避免出现思路太发散、毫无章法导致严重拖长了解决问题的时间,从无序变为有序。
主要分为下面五点:
要有一个事故的上报机制。
事故发生之后,要立刻评估影响范围。
要有快速定位问题的能力。
“止损第一”,先通过最快的方式恢复线上的生产,可能是临时方案或者是终极解决方案。
进行事故的复盘与总结。
下面针对这五点详细的说一下,我们先来看事故的上报机制。
当事故发生的时候可能有几种渠道得到信息的来源。
客户发现系统无法使用进行投诉,这是最不友好的一种。
我们系统内部的值班人员发现系统问题。
我们研发人员通过监控自己发现问题。
当无论是哪一种渠道得知事故发生之后,首先要进行上报。上报到小组leader或者是专门的事故处理群里,让大家都知道这个信息。
我们之前也出现过事故发生后没有及时上报,只是几个研发同学在紧急处理。但线上事故的有的时候可能会比较复杂,并不是表面看起来的那样。比如,明明是A系统报了一个错,但是根源可能不是A系统,A系统可能是只是被影响,根源在B系统。这时候如果没有将事故上报出来,仅仅是A系统的同学在处理,可能最后是花了很长的时间最后定位不是A系统的问题,需要B系统的人进来处理,这个时候就白白浪费了前面的宝贵时间。
所以事故发生后,无论事故的大小,第一步是要先有一个上报机制,让所有人都知道线上系统发生了什么问题,大家一起进行排查。
第二点是评估事故的影响范围。
事故的处理就像一场战役一样。你首先要知道这是一场什么级别的战役。是小规模的冲突?还是局部战役?还是全局的战役?不同级别的战役,处理的方式不同。
所以在着手处理事故之前,我们要先快速的评估出来事故的影响范围是什么?
这里有两点要注意,第一是事故发生的时候尤其重大事故发生的时候大家可能会比较慌乱。每个人都在出谋划策,每个人都在评估范围,各抒己见,这时候噪音比较多。
所以在处理事故的时候,第一点要注意的是必须有一个明确的主要负责人或者是协调人,大家听这个人的统一号令。
另外一点评估影响范围这个事情,要由专人或者是专业的角色来做,不需要每个人都上来评估。我们这边是由测试的同学来负责评估范围。也就是当事故发生的时候。测试同学首要的职责就是评估整个系统影响范围是什么,给出事故的级别。我们事前会将事故定义好不同的级别,根据测试同学评估出来的影响范围来采取不同级别的响应措施。
第三点就是如何快速的定位问题。
测试同学在做范围评估的同时,相关的研发、运维同学就要开始进行定位问题。
定位问题也有几个主要的有效手段。
第一个手段是通过监控或者是告警来判断出错的系统点在哪里。让研发人员有一个大体的范围。
第二点是日志。研发人员在得知一个大体的范围之后,大概知道是哪一个模块可能出现了问题,下一步就需要通过日志来详细确认是否是这个地方出了问题。
这里要注意的是日志在开发的过程中一定要打全,尤其是关键的路径,一定要日志信息,对外的接口调用也一定要有日志信息。经常出现在定位过程中发现关键环节没有打日志,不清楚到底是系统的内部流程问题还是对外调用的问题。一旦发生这种情况,那么将会大大的降低定位问题的效率。
第三点是定位问题时大家的“意识”问题。一旦出现线上事故,这个时候大家不要出现相互甩锅的情况。担心一旦是自己的问题,后续是否会有问责的问题。经常遇到的情况是,大家默认的态度就是,我的系统没问题,如果你说我的系统有问题,请你给出证明。如果有这种意识,那么也会影响解决问题的实效。因为在我们这种分布式微服务的架构中,某个环节出了问题,它会对各个环节的都有影响,产生连锁反应。就像上面的例子一样,表面看起来是用户系统出了问题,但其实用户系统调用了缓存组件,可能是缓存组件出了问题。但缓存组件又部署在虚拟机上,也有可能是虚拟基础的问题。虚拟机之间的通信需要网络,那最终也有可能是网络出了问题。所以一旦用户反馈用户系统不能用,如果仅仅是用户系统的研发在定位问题,可能是花了半个小时的时间,最后确定不是用户系统的问题,是缓存组件的问题。缓存组件的研发又花了10分钟,定位说不是缓存组件的问题,是虚拟机的问题。以此类推,运维同学可能又花了10分钟,最后定位出来是网络的问题。最终可能运维只需要调整一个网络策略的配置就可以解决问题。但是整个过程花了近一个小时的时间。所以在定位问题的时候,各个部门的协调解决问题的意识也非常的重要。出现问题之后,首先要排查自己有没有问题,要先证明自己没有出问题,而不是等着别人证明你有问题。只有当大家同时动起来,才可能从各个角度分析问题,协同起来,快速的将问题定位出来。
最后的一点就是要会抓包。很多问题都是直观但表现在客户端上某个页面打不开,某个流程会报错。那么具体是服务端哪一个接口返回出错了呢?当然一种方式是通过监控来看,这是一种方式,另外还有一种更直观更快速的方式就是通过前端的抓包来快速定位问题点。通过抓包可以判断是域名无法通,还是域名通了之后,后端的请求返回出错以及是具体哪一个请求出错,能够大大的缩小定位的范围。
第四点就是当问题定位出来之后,那么下一步就是怎么样快速的恢复生产。
解决问题大体上分为两种,一种是临时解决方案,一种是终极解决方案。
在处理事故过程中,首先要有一个原则是“优先止损”。因为事故一旦发生,一定会对用户端的体验或者公司有损失,所以解决事故的第一原则是要首先减少这种损失。
根据这一个原则,那么在解决事故的过程中,最重要的就是要快速解决问题。当问题定位到之后,有的时候要根本解决这个问题,可能会要花费比较长的时间,需要修改代码,需要重新发布等等。但用户是不可能等这么长时间的,那这时候要看有没有临时的解决方案,能够快速的先解决问题,等线上的问题解决之后再花时间去从根本上解决这个问题。
这里举两个例子,正好是前段时间线上发生的真实事故。
第一个是前段时间评价系统突然无法评价。用户提交评价的时候会报错,经过研发与dba的定位之后,发现是评价系统的数据库链接数满了,导致数据库达到了瓶颈,无法进行响应。那么为什么数据库链接会突然之间暴涨?这个原因其实还没有找到,但是找到了为什么评价系统无法写入评论数据的原因,就是数据库的链接数已经满了。
这个时候一种方式是我们要找出根本的原因,到底是程序的问题还是数据库的问题导致了链接数一直没有释放,在不断的增加,但是这个过程会比较耗时,可能短时间无法找出真正的原因。另外一种方案就是将进程数量调整下或者数据库重启,先将链接数释放下来解决当前的线上问题。我们的选择首先是将进服务进程数量调整,看看是否会降低链接数。当服务的进程都调整后,仍然没有降低链接数。最后我们采取了重启数据库的方式,重启数据库之后链接数果然降下来了,这时候系统就已经恢复了,线上可以正常的进行评价的操作了。
但是为什么会导致数据库的链接数突然之间爆涨这个原因还没有找到。我们后面又开了专题的分析会去排查,但这个时候的时间压力就没有那么大,可以静下心冷静的去分析复盘这个问题的。
另外一个例子是我们前两天在进行订单中间层的压测。压测之后导致订单中间层出现了异常,APP上查看我的订单详情以及订单列表打不开。
这时候通过研发跟测试的快速定位,发现是订单的中间层没有响应,或者是响应速度已经非常慢了,所以导致正常的用户也打不开。但至于中间层为什么会响应非常慢,这个原因还没有找到。压测的流量已经停止了,但是系统还是无法使用。本着快速止损原则,我们采取将中间层回退到老版本的方案。在做这个新的订单中间层之前我们就已经有预案,如果新的中间层出现问题,我们会有方案快速的回退到老版本。通过这个预案,我们很快的将线上的业务问题解决掉了。可以正常的在APP上打开订单列表以及订单详情了。然后我们又花时间去定位为什么当时压测之后导致新的中间层打不开。这里有一点很重要,就是凡事要有PLAN B,也就是预案。每次发布新系统、新功能都要有预案,一旦这次发布失败需要怎么做,怎么样去解决这个问题。
最后一步就是事故的复盘总结。
事故的复盘总结,要问自己5个问题。
为什么会发生这个事故?为什么没有测试到这个线上的问题?为什么没有第一时间系统检测到这个事故?为什么会花这么长时间解决问题?下一次该如何避免类似的问题?
将这5个问题一一回答了,才达到了真正的复盘的目的。事故复盘还有另外一点要注意的,就是对于复盘中提出的后续优化的策略,要有一个明确的时间点以及具体的优化方案,要有相关的同学进行跟进,是否真正落实到位的。
因为有些优化策略是一个比较大的动作,可能需要相对较长的时间去做,如果没有人跟进的话,这个事情可能后面就会不了了之,后面可能又会因为这个事情有没有做而发生类似的问题,所以事故的复盘要闭环,要先找出问题的本质原因,然后怎么去解决这个问题,什么时间去解决,这样才是真正的将问题闭环掉了,避免同一个问题再次发生。