<audio id="audio" title="06 | 故障发现：如何建设On-Call机制？" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/63/8f/634329a384810be3071d1a3b3fe2c38f.mp3"></audio>

你好，我是赵成，从今天开始，我们进入课程实践篇的内容。

在上一部分，我们学习了SRE的基础，需要掌握的重点是SLI和SLO以及Error Budget（错误预算）策略。SLI是我们选择的衡量系统稳定性的指标，SLO是每个指标对应的目标，而我们又经常把SLO转化为错误预算，因为错误预算的形式更加直观。转化后，我们要做的稳定性提升和保障工作，其实就是想办法不要把错误预算消耗完，或者不能把错误预算快速大量地消耗掉。

这么说，主要是针对两种情况：一种是我们制定的错误预算在周期还没有结束之前就消耗完了，这肯定就意味着稳定性目标达不成了；另一种情况是错误预算在单次问题中被消耗过多，这时候我们也要把这样的问题定性为故障。

今天，我们就来聊一聊，为了最大程度地避免错误预算被消耗，当我们定义一个问题为故障时，我们应该采取什么措施。

## 聚焦MTTR，故障处理的关键环节

好了，我们先回顾下在第1讲的时候，提到故障处理的环节就是MTTR，它又细分为4个指标：MTTI、MTTK、MTTF和MTTV，之所以分组分块，也是为了更加有目的性地做到系统稳定性。

<img src="https://static001.geekbang.org/resource/image/3d/dd/3dd910e354da003e234b0340b68e76dd.jpg" alt="">

那么，这四个环节，在我们故障处理MTTR又各自占多长时间呢？下面这个MTTR的时长分布图，是IBM在做了大量的统计分析之后给出的。<br>
<img src="https://static001.geekbang.org/resource/image/e5/fd/e5b28b0bed414afe8feda4f67b21a6fd.jpg" alt=""><br>
我们可以看到，MTTK部分，也就是故障定位部分的时长占比最大。这一点，我们应该都会有一些共鸣，就是绝大部分的故障，往往只要能定位出问题出在哪儿了，一般都可以快速地解决故障，慢就慢在不知道问题出在哪儿，所以说我们大部分时间都花在寻找问题上了。

不过，从我实际分析的情况看，很多时候MTTR的时间分布跟这个图会有一些差别，为什么呢？

因为上面这张图是IBM针对网络设施的故障统计出来的，鉴于网络设备部署模式相对简单，以及日志和报错信息比较固定和明确，所以出现问题时，MTTI的判定阶段不会花太多时间。而且真的出现问题，基本上采取的策略一般也是定位到根因，再采取措施处理故障，除了主备切换等冗余措施，基本是没有太多其它手段。

但是，在一个分布式的软件系统下，我们判定一个问题发生在哪儿，影响范围到底是怎么样的，要召集哪些人共同参与定位排查等等，这个反而会消耗更多时间，所以我们看到MTTI阶段占比会更重。

另外，当一个分布式系统发生故障时，我们的策略一定不是找到根因，而是优先恢复业务。所以，我们往往是通过故障隔离的方式，先快速恢复业务，也就是我们经常听到的Design for Failure这样的策略，再具体一点，就是服务限流、降级、熔断甚至是主备切换这样的手段，这样的话，MTTK的占比会有所下降。

因此，从分布式系统的实际情况来看，整个MTTR的时间占比分布大致是这样的：<br>
<img src="https://static001.geekbang.org/resource/image/8e/ac/8e55074c8ec8e2c741ebeac7f7ae80ac.jpg" alt=""><br>
其实，不管是不是分布式系统，我们针对处理故障的目的都是比较明确的，就是要提升每个环节的处理效率，缩短它们的处理时间，这样才会缩短整个MTTR，减少对不可用时长的消耗。

今天，我们就先来看MTTR的第一个环节，MTTI。看看在MTTI这个环节我们可以采取哪些措施来提高处理故障效率。关于MTTR中的另外三个环节，也就是MTTK、MTTF和MTTV我们会在后面的课程中继续讨论。

## MTTI：从发现故障到响应故障

MTTI，就是故障的平均确认时间，也就是从故障实际发生时间点，到触发采取实际行动去定位前的这段时间。

这个环节其实主要有两件事情要做：**第一件事，判断出现的问题是不是故障；第二件事，确定由谁来响应和召集**。我们一一来看。

先看第一件事。我们平时遇到的问题很多，但是这些问题的影响不见得都很严重，或者都需要我们立即做出响应去处理。即便是故障，我们也会分不同的响应级别去处理。那我们怎么判断出现的问题是不是故障呢？如果是故障，我们应该以哪种级别去响应呢？

解决方案很明确，就是利用我们在[《04 | 错误预算：达成稳定性目标的共识机制》](https://time.geekbang.org/column/article/215649)中讲过的，根据错误预算制定故障等级的方式来判定响应方式。我们把trade_cart购物车的案例再拿出来，你可以再看下，作为参考。<br>
<img src="https://static001.geekbang.org/resource/image/cc/c6/cc0987ffd5d5d9391bc58eb505c6ecc6.jpg" alt=""><br>
在没有SLO和错误预算这个体系时，我们通常会根据用户投诉，或客服对同一问题的重复反馈来判断。比如10分钟内，有超过50个用户投诉无法购买商品、支付不成功或者优惠券未生效等问题，我们就会启动应急响应。不过，一旦等用户和客服反馈，就说明故障影响已经非常恶劣了，用户也已经处于无法忍受的状态了。

显然这种方式并不高效。既然我们已经搭建了SRE体系，设定了SLO，能对稳定性进行量化管理，那我们就能比用户更快发现问题并响应问题了。至于用户投诉和客服反馈的渠道，只能是作为我们的辅助手段。

所以，我们可以根据设定的SLO和错误预算，准确判断发生的问题是否是故障，并依据故障等级决定我们采取什么样的措施去处理这些问题，大大提高反应效率。

接着来看第二件事，谁来响应和召集。这件事很容易理解，如果我们判定这个问题就是一个故障，首先要有人能判定，接下来需要哪些人来介入，并能够把相关的人员召集起来，一起来处理故障。

这两件事，其实就是SRE里面提到的**On-Call机制**。

我们可以看到，第一件事其实主要依赖于我们的监控和告警体系。这里我想再强调一下，在On-Call阶段，并不是所有的告警我们都要响应，如果不影响稳定性，一般的告警是可以降低响应级别的，我们只需要响应基于SLO的告警。

我和很多公司交流过，发现大家都非常重视监控体系的建设，监控指标梳理得也非常全面，而且各种监控技术和产品都会使用。比如，从最早的Zabbix，以及日志系统栈ELK，再到近两年随着Kubernetes而火爆起来的Prometheus等等，从技术上来说，这一点不是太大的问题。但是，第二件事往往容易被我们忽视，也就是On-Call的流程机制建设。

## 关于On-Call的两个案例

在正式讲流程机制之前，我先分享两个关于On-Call的案例。

第一个案例是发生在我自己团队里的，当时遇到一次大数据产品HBase故障。那是一个周六的下午，负责数据平台的运维同学收到了故障告警，出现了部分节点不可用，同时依赖该产品的搜索和推荐等业务也开始反馈异常，进而影响到广告曝光，导致资金损失。

问题出现后，我们很快明确了故障的严重程度，开始联系对应的负责人上线一起处理。因为是周末，所以需要一个个打电话联系，同时我们的HBase已经上云，所以处理过程又需要云产品的同事介入，这就又涉及到跨组织的协调。云产品内部又有分工，一线服务、二线产品研发支持，所以这个协调过程又是一个比较长的链条。再加上其他的权限问题，所以等相关人员就位开始真正排查问题的时候，距离发生故障已经有很长一段时间了。

当时我大致统计了下，仅仅协调人员到位并上线开始处理问题，这个过程就花去了45分钟，而真正解决问题的环节只用了15分钟。

第二个例子是国内第一大企业IM产品。因为产品本身的特点，每天早上八点半到九点，会有一波使用高峰，产品经常在这个时间段出故障。同时呢，这个时间段正好是互联网公司通勤时间，大部分技术员工都在上班的路上，根本没办法处理问题，导致故障时间过长。

所以为了保证及时响应，企业决定分批上下班，一批人早上在家值守，甚至是守在电脑旁随时应急，其他员工准时上班。等过了产品使用高峰期，值守的员工再陆续从家里出发上班。同时，下班也错开时间，保证有人可以及时响应。

这种错时保障机制，很多电商企业在大促保障或者重大活动期间也经常用，就是**确保关键角色必须在线，随时应急响应**。

通过以上两个案例，我们发现从整体上讲，如果要缩短MTTI时长，技术相关的监控告警很重要，但更关键的是一整套协作机制。这也是为什么像Google这样技术体系已经如此完善的公司，还要强调On-Call机制的重要性。

那么，我们怎样才能建设好On-Call 的流程机制呢？

## On-Call的流程机制建设

接下来，我就跟你说说，在蘑菇街我们是怎么做的，我把这个流程总结为“**On-Call关键5步法**”。

1.**确保关键角色在线。**

这里的关键角色不是指一两个值班的运维或SRE人员，而是整个产品体系中的所有关键角色。比如电商就需要安排核心业务应用（如用户、商品、交易、优惠及支付等）的Owner，或Backup中至少有一人参与On-Call轮班。不过，接收故障告警或第一时间响应故障的，一般是运维、PE或SRE这样的角色，业务开发同事要确保及时响应SRE发起的故障应急。

2.**组织War Room应急组织。**

我们有专门处理故障的“消防群”（暗含着灭火的意思），会将这些关键角色纳入其中，当有故障发生时会第一时间在消防群通报，这时对应的On-Call同事就要第一时间最高优先级响应呼叫（Page）。如果是工作日，对于严重故障，会立刻组织成立War Room，责任人会马上聚到一起；如果是非工作时间，则会通过电话会议的方式拉起虚拟War Room。

3.**建立合理的呼叫方式。**

在On-Call的落地过程中，我们经常会遇到的一种情况，就是谁最熟悉某个系统，谁就最容易被7*24小时打扰。比如系统或应用的Owner或者是架构师，出现问题的时候一定是找这些同事处理的效率最高，所以就会造成这些同事被默认为On-Call。

但是这样做会极大地影响这些同事在正常业务开发上的精力投入。他们要么总是被打断，要么就是经常通宵处理问题，导致第二天无法正常工作，甚至在非工作日也得不到正常的休息。

这种情况下，我们建议使用固定的On-Call手机，建立手机与所有On-Call系统的对应关系，比如这个手机号码对应交易核心应用，另一个号码对应IDC机房运维等等。这样我们在On-Call时就不再找具体的哪个人，而是手机在谁手中，谁就承担On-Call职责。除非问题迟迟得不到解决，或者遇到了疑难杂症，这种时候再呼叫其他同事参与进来。

无论是SRE、架构师，还是一线开发，**熟悉某个系统的最快最好的方式就是参与On-Call，而不是看架构图和代码。**所以，有效的On-Call机制，可以让团队更深刻地认识到目前系统的存在哪些问题，对自己的痛苦状态也会有更深刻的感受，进而对后面的改进措施才能更有针对性和落地性。同时，On-Call也可以培养和锻炼新人和Backup角色，这也是让新人尽快融入团队和承担责任的最好的方式。

4.**确保资源投入的升级机制。**

这个跟前面几条有相关性，有很多团队认为On-Call就是设置几个人值班，所有的事情都交给这几个人做；最极端的还会认为所有的事情，都应该是冲在最前线的运维或SRE来完成。但是，在分布式架构这种复杂场景下，这种思路是明显不可行的。

这里最核心的一点就是要给到运维和SRE授权，当他发现问题不是自己或现有On-Call人员能解决的时候，他有权调动其他必要资源投入。如果故障等级偏高，一下无法明确具体找哪些人员投入的时候，SRE或运维可以直接上升到自己的主管或相关主管那里，要求上级主管协调资源投入。必要时，还可以上升到更高级主管，甚至CTO或技术VP来关注。所以，授权非常关键，这一点的具体操作层面，我们会在后面的故障处理过程中再详细介绍。

5.**与云厂商联合的On-Call。**

现在企业上云是大势所趋，绝大多数情况下，我们对问题和故障的处理，是离不开与云产品工程师一起高效联动的。所以，我们应该把云产品和云厂商作为我们系统的一部分，而不是单纯的第三方。而对于云厂商来说，也要考虑把客户业务作为自身业务的一部分，只有这样双方才能紧密合作。我们应该提前做好与云厂商之间的协作磨合，联合故障演练，必要的授权等等。

## 总结

最后，我们做一下简单的总结。

我们按照MTTR的细化分段可以看到，处理故障的第一个环节就是MTTI，也就是故障发现阶段。这个阶段，我们要靠基于SLO的告警，更加精准地告知我们当前系统的稳定性出现的问题，并根据对SLO的影响程度，也就是错误预算的消耗情况作出判断，是否定性成故障。如果是故障，我们就要启动应急响应，而高效快速的应急响应，是要靠On-Call的流程机制来保证的。

关于建设On-Call的流程机制，我给你分享了我自己团队的“On-Call关键5步法”，咱们再一起复习一下：

1. 确保关键角色在线；
1. 组织War Room应急组织；
1. 建立合理的呼叫方式；
1. 确保资源投入的升级机制；
1. 与云的联合On-Call。

当我们能够很好地做到以上两点的时候，我们就能大幅降低MTTI，也为接下来更高效的故障定位和恢复打下了坚实的基础。

## 思考题

最后，给你留一个思考题。

学完本节课的内容后，你觉得在故障处理中，是优先建设监控体系更重要，还是建设高效的On-Call机制更重要？它们两者应该怎么来结合会更有效？欢迎你在留言区分享你的思考。

如果你在On-Call方面也积累了一些经验，请分享在留言区，也欢迎你把今天的内容分享给身边的朋友。

我是赵成，我们下节课见。
