<audio id="audio" title="24 | 监控设计，让一切都有迹可循，尽在掌控" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/78/57/78fba3dd9b1e6d3e9c19f09da8505257.mp3"></audio>

你好，我是乔新亮。

这一讲，我想和你聊聊如何做好监控设计。

你可能会想，为什么要聊监控呢？做监控不是很简单吗？

所有做技术的同学，基本都会根据公司的日志规范，在代码中打印 Log ，以记录告警和报错。许多企业，也会将日志收集分析，以此形成对系统状态的监控。如果条件允许，团队还可以使用各类免费或付费的服务器监控报警服务，多方便啊，这有啥好讲的呢？

其实在我眼里，这些都只是构成了监控的一部分，并非完整的监控体系。要想深刻理解监控的概念，我们首先要学会问自己：为什么要做监控系统？这就像许多工作方法论里强调的一样，做事先问目的 —— “start with why”。

**监控的目标是及时发现系统的问题，并尽可能快地做出相应的动作，让系统一直处于健康的状态**。监控，可以拆分为“监”和“控”分别理解，其含义恰好对应着两种主要手段，也就是“**监视**”和“**控制**”（中文真是博大精深）。

比如说，生产环境出现了个 bug，怎样定位问题？这需要做好“监视”；发现问题根源后如何正确响应？这需要做好“控制”。

比较无奈的情况是，研发人员知道系统出了问题，但无法定位问题；更悲催的情况是，研发人员能够定位问题，但无法控制问题，只能眼睁睁地看着故障发生。但无论哪种情况发生了，从结果来看，其实区别都不大。唯一的区别可能是，前者至少让人心存希望，后者则让人感觉整颗心都“冰凉冰凉”的。

说到这里，我不禁有点感慨：监控、监控，意味着既要监视也要控制，没有控制的监视达不到目标，没有监视的控制无法形成行动计划。

从业至今，我曾处理过许多因认知不足，而导致的系统监控问题。下面，我们就选取其中一件比较典型的案例，尝试着一同复盘下。

## 技术团队的“怪现象”

这个案例发生于某日下班后 —— 大约是在傍晚 20:00 左右，团队发现了一个出现在生产环境的异常。该异常来自一个可以连接众多终端设备的程序，其具体表现为：所在服务器的 CPU 负载突然飙升。但发现异常后，团队既无法将其恢复，也无法定位问题。

发现问题后，共有十几位工程师先后参与了问题分析。很快，两个小时就过去了，监控系统仍然显示 CPU 占用异常，问题还是没有解决。这下，产品负责人着急了，向我求助，并将我拉进了问题调查组的电话会议。

进入会议后，我立刻问了大家一个问题：

“最近线上有什么版本变动吗？都回退了吗？”

团队回答道：“都回退了。”

我几乎没有任何犹豫地说道，不可能，一定没有全部回退。

要知道，计算机是非常可靠的。如果一套代码在一台机器上可以正常、稳定地运行，那么在外部环境没有发生任何变更的情况下，一周、一个月、一年后，它大概率能继续保持正常、稳定地运行。

你可能会想，老乔又开始信口胡说了，难道就没有意外情况吗？

有，我也确实遇见过，但在近 20 年职业生涯里，我只遇见过一次（ZooKeeper 因虚拟机连接数过多而崩溃事件，在“高可用设计”部分，我们曾简单提到）。所以，这种情况几乎是“可遇不可求”的，在大部分时间里都可以直接忽略。

果然，在我的追问下，负责发布的同学说，系统没有回退到上一个版本，而是按研发同学的指挥选择性回退的。

好呀，真相大白，我命令他迅速按公司研发制度回退。

没成想，回退到上一版本后，系统依然不正常。于是，团队继续查看前端、服务端、数据库等各类监控数据，试图分析问题到底出在哪里。

我再一次找到团队，问道，真的都回退了吗？

团队可怜兮兮地回答，真的都回退了！

我的回答是，不可能，鬼才信你们…… 于是，我开始继续不依不饶地追问。

终于，在我的“威逼利诱”下，有位同学一拍脑门，犹豫地说道：“我在数据库里加了条索引，不过这肯定不会导致负载异常……”

还没说完，我就哭笑不得地打断了他的话，谈这些做什么？赶紧回退去。

当这个改动回退后，一切都恢复了正常。

最终，一个本该三分钟内被搞定的生产问题，用了几个小时才解决。幸亏发布窗口是业务低峰期，否则已酿成重大损失。在许多公司里，相关人员几乎一定会受到处罚。

事后复盘时，我问团队，当我询问版本有无全部回退时，为何不及时声明？

那个同学委屈地说，我以为那条索引不可能惹出这么大的问题……

请注意，在这个故事里，当事人员并不是毫无经验的新手；公司并非没有监控系统，相反还做到了可视化、图形化。

既然如此，为何团队还会被一条小小的索引命令阻滞这么久呢？这是一个非常奇怪的现象。而且，在参加 GTLC 全球技术领导力峰会时，我在和一些同学的沟通中也发现：这种现象并非孤例，很多团队都曾出现过类似的情况。

于是，我不得不去思考，IT 团队的系统监控体系，到底出了什么问题？

## IT 团队的系统监控体系，到底出了什么问题？

当陷入思考的泥潭时，我们往往需要将思维抽离，尝试站在更高维度探寻问题的本质。此时，我们不妨将这个案例暂且放一放，重新思考一下监控的本质含义。

在文章开头，我们讲过了，**监控是为了让系统一直处于健康状态，具体的手段包括“监视”和“控制”两种**。简单来说，就是当生产环境出现问题时，我们要能知道哪里出了问题，并具备相应的控制手段。

生产环境应急恢复的最大挑战在于根因分析，即找到问题的根本原因，这往往是耗时最久的工作。

但如果没有控制手段，那么即使找到了根因，团队也是无能为力，只能干着急，或者静静地期盼奇迹出现，好像系统在下一分钟就能自动恢复健康。

所以，当生产环境发生异常时，大部分团队会这样组织故障恢复工作：

1. 发现问题后，立即联系各相关系统负责人，以便共同排查问题；
1. 要求大家在一分钟之内回复：自己治下的系统或服务是否健康（这里要将“健康”的定义想清楚，如，响应时间是否增加超过 30% 等）；
1. 进行根因分析，确认导致问题的系统、服务；
1. 完成系统恢复工作。

对于步骤  1、2 ，其实挑战都不大，真正的挑战在于步骤  3、4。步骤 3 依赖于相关分析人员的专业程度。一般情况下，随着企业业务的复杂度逐渐增加、系统和服务的数量逐渐增加，人员规模也会越来越大，在步骤 3 上花费的时间就会脱离控制。

此外，对于步骤  3 中涉及的不健康组件，我们需要分析：这种不健康状态是原因，还是结果。关于分析方法，其实也比较简单：

1. 首先，我们要确认异常是外因导致，还是内因导致。比如，服务响应慢，既可能是因为外部调用量变大，也可能是因为内部进程繁忙，导致 I/O 、内存、网络资源发生争抢。这步判断相对来说比较耗时间，只有当调查足够充分时，结果才可能浮出水面；
1. 无论是内因还是外因，都要“顺藤摸瓜”，继续进行排查，最后进行恢复。

说到这里，我们不难得出结论：生产应急保障体系的建设，并不像大家想象的那么简单。从系统复杂度到人员专业性，任何不足都会导致问题定位、根因分析花费更多的时间。因此，以上故障恢复流程也存在很大的隐患。

那么，难道生产系统出了问题，我们就只能坐以待毙吗？有没有一个对团队专业度依赖较低的方法呢？答案是，有的。我把它总结为：**流控和版本回退，简单、粗暴、实用**。

流控，就是做好程序的并发流量控制；版本回退，就是在生产环境的发布出现问题时，及时回退到上一个版本。

**生产环境出现问题，原因通常只有两个字：变化**。常见的“变化”大致有三类：

1. 外部用户请求量增大；
1. 产品发布，一般包括代码发布、配置发布、SQL 脚本发布等；
1. 依赖资源变化，一般是计算、存储、网络基础设施情况变差，比如磁盘存在坏道等。

这样看来，当故障发生时，我们不一定要组织团队进行复杂的根因分析 —— 那是故障恢复后的事儿。相反，只要我们控制住了服务的近期变化，也就等于控制住了故障。思路一变，好像就豁然开朗了。所以， 我们不妨将生产应急恢复方法修改为以下 4 条：

1. 发现问题后，立即联系各相关系统负责人，以便共同排查问题；
1. 要求大家在一分钟之内回复：自己治下的系统或服务是否健康（这里要将“健康”的定义想清楚，如，响应时间是否增加超过 30% 等）；
1. 此处组织两批研发力量，并行工作。第一批解决专业问题，继续跟进问题的定位和调试；第二批负责消灭变化，对有变化的模块进行回退，对于外部请求数量升高的模块启动流控；
1. 恢复系统。

你看，这样就降低了故障恢复对于团队专业性的要求。只要我们保证，对于任何组件，都有以下两种手段同时存在：

1. 流控手段；
1. 发布回退手段。

是不是很简单？在 IT 行业，对于专业团队而言，一般没有太过复杂的工作；如果工作过于复杂，往往是因为负责人不够专业。还是那句话：大道至简。

问题的关键在于，生产环境是不允许查找 bug 的。**在生产环境，研发人员应该寻找并消灭“变化”。从寻找 bug 到寻找变化，是一个非常大的认知转变。**

此时，再回顾文章开头的案例，答案就比较清晰了。团队在执行生产环境故障恢复工作时，接连犯下了三个错误：

错误一：负责发布的同学，没有按规定回退至稳定版本，而是询问开发同学的意见，并以其意见为准；

错误二：相关负责人，因为假设“一条索引不会导致故障”而知情不报，导致系统无法完全回退；

错误三：十几名团队成员没有将精力聚焦在线上业务恢复方面，而是试图在生产环境查找 bug。

三个错误如出一辙，全部来自于技术同学的思维惯性。在大家的认知里，制度就是拿来参考的，对应模块的负责人才是专业的，出了事先找人再问制度规范，或者压根不问制度；在大家的认知里，bug 要用排除法解决，“确定”没问题的模块就要排除在外；在大家的认知里，能一眼发现错误的程序员，才是技术高手，如果动不动就回退，和“网管只会重启”有什么区别？

但是我想说的是，当问题发生时，你的潜意识是要找到 bug ，还是找到变化，对应的结果可能是完全不同的。我们的目标是，**即使找不到 bug，依然可以做好故障恢复**。

这样的思维惯性有多么普遍呢？我们举个例子：你是否曾在下班回家的路上，被老板电话叫回公司，查找线上 bug  ？

也许你会觉得这样做很合理，但听完这节课以后，希望你能够意识到这种做法的局限性：线上有 bug ，为什么需要研发立刻回公司？先回退就好了嘛。否则，研发现场写程序，压力也是挺大的。

更别提，一些团队还经常出现喜剧性的一幕：生产环境出现了问题，研发火急火燎地改了个版本，结果系统做不到秒级发布，单是发布就用了半个小时。好不容易上线了，还没来得及高兴，就发现了个新问题……

我们必须不断强调并加深印象：**生产环境永远不允许调试问题，出现问题立刻回退，查问题要去测试环境**。

你可能会想，老乔啊，你这就有点纸上谈兵了，很多大型发布涉及多个系统，怎么可能随便回退呢？

其实这个问题，亚马逊在十几年前就给出解决方案了：**大版本立项，小版本上线** —— 梳理好各模块的依赖关系，将各个系统、各个服务独立发布。当然，这也需要依赖服务版本化和 CI  能力的支持。

以上我们讲的是对企业系统的监控。除此之外，我们也要做好对企业业务的监控。

也就是说，对于企业任何一个未处于理想状态的业务环节，都要进行监控：做好问题的可视化展现、明确管理执行动作，通过数据化管理，不断完善企业的运营效率和运营质量。道理其实还是相通的。

如果能做到监视一切，分析一切，控制一切，“眼”能看见所有，“脑”能洞察一切，“手”能一手遮天，一切业务数字化，一切数据可视化，一切控制可触发，那么，这个企业的数字化水平一定已经很高了。

## 结语

今天，我们从一个实际案例出发，主要聊了聊关于企业生产环境系统监控的认知和方法：**监控的目的是让系统一直处于健康状态，具体手段则可分为“监视”和“控制”两种；要做好控制，一个重要的方法是做好流控和版本回退。因为在大部分情况下，消除变化就等于消除异常。**

实际上，不单是技术、业务系统需要做好监控，研发管理、团队管理都要做好监控。

关于研发管理，我们在“高可用设计”部分曾提到：风险是经由开发环境、SIT 环境、压测环境、PRE 环境，进入生产环境的。所以我们要做的是严格检查各个环境下的异常。所谓研发管理规范，应该为代码版本进入下一个环境设置准入标准。对于任何异常，都有负责人进行修正。

对于团队管理，我们常常说，组织是结果导向的，但管理工作是过程导向的。关注过程自然就会得到好的结果，只盯着结果往往什么也得不到。对于一个项目、一个产品，乃至于团队的健康度，管理者有没有在关键节点设置监控？有没有针对异常做好控制？其差别是巨大的。

如果你认真学习了前面的内容，可能也会发现，无论是管理还是专业技术，很多关键认知都是相通的。很多时候，是“一理通百理明”。在学习的同时，前后交叉思考，也有助于你在更高的维度上掌握这些知识。

今天，我们就聊到这里，下一讲再见。
