# 24 | 监控设计,让一切都有迹可循,尽在掌控 你好,我是乔新亮。 这一讲,我想和你聊聊如何做好监控设计。 你可能会想,为什么要聊监控呢?做监控不是很简单吗? 所有做技术的同学,基本都会根据公司的日志规范,在代码中打印 Log ,以记录告警和报错。许多企业,也会将日志收集分析,以此形成对系统状态的监控。如果条件允许,团队还可以使用各类免费或付费的服务器监控报警服务,多方便啊,这有啥好讲的呢? 其实在我眼里,这些都只是构成了监控的一部分,并非完整的监控体系。要想深刻理解监控的概念,我们首先要学会问自己:为什么要做监控系统?这就像许多工作方法论里强调的一样,做事先问目的 —— “start with why”。 **监控的目标是及时发现系统的问题,并尽可能快地做出相应的动作,让系统一直处于健康的状态**。监控,可以拆分为“监”和“控”分别理解,其含义恰好对应着两种主要手段,也就是“**监视**”和“**控制**”(中文真是博大精深)。 比如说,生产环境出现了个 bug,怎样定位问题?这需要做好“监视”;发现问题根源后如何正确响应?这需要做好“控制”。 比较无奈的情况是,研发人员知道系统出了问题,但无法定位问题;更悲催的情况是,研发人员能够定位问题,但无法控制问题,只能眼睁睁地看着故障发生。但无论哪种情况发生了,从结果来看,其实区别都不大。唯一的区别可能是,前者至少让人心存希望,后者则让人感觉整颗心都“冰凉冰凉”的。 说到这里,我不禁有点感慨:监控、监控,意味着既要监视也要控制,没有控制的监视达不到目标,没有监视的控制无法形成行动计划。 从业至今,我曾处理过许多因认知不足,而导致的系统监控问题。下面,我们就选取其中一件比较典型的案例,尝试着一同复盘下。 ## 技术团队的“怪现象” 这个案例发生于某日下班后 —— 大约是在傍晚 20:00 左右,团队发现了一个出现在生产环境的异常。该异常来自一个可以连接众多终端设备的程序,其具体表现为:所在服务器的 CPU 负载突然飙升。但发现异常后,团队既无法将其恢复,也无法定位问题。 发现问题后,共有十几位工程师先后参与了问题分析。很快,两个小时就过去了,监控系统仍然显示 CPU 占用异常,问题还是没有解决。这下,产品负责人着急了,向我求助,并将我拉进了问题调查组的电话会议。 进入会议后,我立刻问了大家一个问题: “最近线上有什么版本变动吗?都回退了吗?” 团队回答道:“都回退了。” 我几乎没有任何犹豫地说道,不可能,一定没有全部回退。 要知道,计算机是非常可靠的。如果一套代码在一台机器上可以正常、稳定地运行,那么在外部环境没有发生任何变更的情况下,一周、一个月、一年后,它大概率能继续保持正常、稳定地运行。 你可能会想,老乔又开始信口胡说了,难道就没有意外情况吗? 有,我也确实遇见过,但在近 20 年职业生涯里,我只遇见过一次(ZooKeeper 因虚拟机连接数过多而崩溃事件,在“高可用设计”部分,我们曾简单提到)。所以,这种情况几乎是“可遇不可求”的,在大部分时间里都可以直接忽略。 果然,在我的追问下,负责发布的同学说,系统没有回退到上一个版本,而是按研发同学的指挥选择性回退的。 好呀,真相大白,我命令他迅速按公司研发制度回退。 没成想,回退到上一版本后,系统依然不正常。于是,团队继续查看前端、服务端、数据库等各类监控数据,试图分析问题到底出在哪里。 我再一次找到团队,问道,真的都回退了吗? 团队可怜兮兮地回答,真的都回退了! 我的回答是,不可能,鬼才信你们…… 于是,我开始继续不依不饶地追问。 终于,在我的“威逼利诱”下,有位同学一拍脑门,犹豫地说道:“我在数据库里加了条索引,不过这肯定不会导致负载异常……” 还没说完,我就哭笑不得地打断了他的话,谈这些做什么?赶紧回退去。 当这个改动回退后,一切都恢复了正常。 最终,一个本该三分钟内被搞定的生产问题,用了几个小时才解决。幸亏发布窗口是业务低峰期,否则已酿成重大损失。在许多公司里,相关人员几乎一定会受到处罚。 事后复盘时,我问团队,当我询问版本有无全部回退时,为何不及时声明? 那个同学委屈地说,我以为那条索引不可能惹出这么大的问题…… 请注意,在这个故事里,当事人员并不是毫无经验的新手;公司并非没有监控系统,相反还做到了可视化、图形化。 既然如此,为何团队还会被一条小小的索引命令阻滞这么久呢?这是一个非常奇怪的现象。而且,在参加 GTLC 全球技术领导力峰会时,我在和一些同学的沟通中也发现:这种现象并非孤例,很多团队都曾出现过类似的情况。 于是,我不得不去思考,IT 团队的系统监控体系,到底出了什么问题? ## IT 团队的系统监控体系,到底出了什么问题? 当陷入思考的泥潭时,我们往往需要将思维抽离,尝试站在更高维度探寻问题的本质。此时,我们不妨将这个案例暂且放一放,重新思考一下监控的本质含义。 在文章开头,我们讲过了,**监控是为了让系统一直处于健康状态,具体的手段包括“监视”和“控制”两种**。简单来说,就是当生产环境出现问题时,我们要能知道哪里出了问题,并具备相应的控制手段。 生产环境应急恢复的最大挑战在于根因分析,即找到问题的根本原因,这往往是耗时最久的工作。 但如果没有控制手段,那么即使找到了根因,团队也是无能为力,只能干着急,或者静静地期盼奇迹出现,好像系统在下一分钟就能自动恢复健康。 所以,当生产环境发生异常时,大部分团队会这样组织故障恢复工作: 1. 发现问题后,立即联系各相关系统负责人,以便共同排查问题; 2. 要求大家在一分钟之内回复:自己治下的系统或服务是否健康(这里要将“健康”的定义想清楚,如,响应时间是否增加超过 30% 等); 3. 进行根因分析,确认导致问题的系统、服务; 4. 完成系统恢复工作。 对于步骤 1、2 ,其实挑战都不大,真正的挑战在于步骤 3、4。步骤 3 依赖于相关分析人员的专业程度。一般情况下,随着企业业务的复杂度逐渐增加、系统和服务的数量逐渐增加,人员规模也会越来越大,在步骤 3 上花费的时间就会脱离控制。 此外,对于步骤 3 中涉及的不健康组件,我们需要分析:这种不健康状态是原因,还是结果。关于分析方法,其实也比较简单: 1. 首先,我们要确认异常是外因导致,还是内因导致。比如,服务响应慢,既可能是因为外部调用量变大,也可能是因为内部进程繁忙,导致 I/O 、内存、网络资源发生争抢。这步判断相对来说比较耗时间,只有当调查足够充分时,结果才可能浮出水面; 2. 无论是内因还是外因,都要“顺藤摸瓜”,继续进行排查,最后进行恢复。 说到这里,我们不难得出结论:生产应急保障体系的建设,并不像大家想象的那么简单。从系统复杂度到人员专业性,任何不足都会导致问题定位、根因分析花费更多的时间。因此,以上故障恢复流程也存在很大的隐患。 那么,难道生产系统出了问题,我们就只能坐以待毙吗?有没有一个对团队专业度依赖较低的方法呢?答案是,有的。我把它总结为:**流控和版本回退,简单、粗暴、实用**。 流控,就是做好程序的并发流量控制;版本回退,就是在生产环境的发布出现问题时,及时回退到上一个版本。 **生产环境出现问题,原因通常只有两个字:变化**。常见的“变化”大致有三类: 1. 外部用户请求量增大; 2. 产品发布,一般包括代码发布、配置发布、SQL 脚本发布等; 3. 依赖资源变化,一般是计算、存储、网络基础设施情况变差,比如磁盘存在坏道等。 这样看来,当故障发生时,我们不一定要组织团队进行复杂的根因分析 —— 那是故障恢复后的事儿。相反,只要我们控制住了服务的近期变化,也就等于控制住了故障。思路一变,好像就豁然开朗了。所以, 我们不妨将生产应急恢复方法修改为以下 4 条: 1. 发现问题后,立即联系各相关系统负责人,以便共同排查问题; 2. 要求大家在一分钟之内回复:自己治下的系统或服务是否健康(这里要将“健康”的定义想清楚,如,响应时间是否增加超过 30% 等); 3. 此处组织两批研发力量,并行工作。第一批解决专业问题,继续跟进问题的定位和调试;第二批负责消灭变化,对有变化的模块进行回退,对于外部请求数量升高的模块启动流控; 4. 恢复系统。 你看,这样就降低了故障恢复对于团队专业性的要求。只要我们保证,对于任何组件,都有以下两种手段同时存在: 1. 流控手段; 2. 发布回退手段。 是不是很简单?在 IT 行业,对于专业团队而言,一般没有太过复杂的工作;如果工作过于复杂,往往是因为负责人不够专业。还是那句话:大道至简。 问题的关键在于,生产环境是不允许查找 bug 的。**在生产环境,研发人员应该寻找并消灭“变化”。从寻找 bug 到寻找变化,是一个非常大的认知转变。** 此时,再回顾文章开头的案例,答案就比较清晰了。团队在执行生产环境故障恢复工作时,接连犯下了三个错误: 错误一:负责发布的同学,没有按规定回退至稳定版本,而是询问开发同学的意见,并以其意见为准; 错误二:相关负责人,因为假设“一条索引不会导致故障”而知情不报,导致系统无法完全回退; 错误三:十几名团队成员没有将精力聚焦在线上业务恢复方面,而是试图在生产环境查找 bug。 三个错误如出一辙,全部来自于技术同学的思维惯性。在大家的认知里,制度就是拿来参考的,对应模块的负责人才是专业的,出了事先找人再问制度规范,或者压根不问制度;在大家的认知里,bug 要用排除法解决,“确定”没问题的模块就要排除在外;在大家的认知里,能一眼发现错误的程序员,才是技术高手,如果动不动就回退,和“网管只会重启”有什么区别? 但是我想说的是,当问题发生时,你的潜意识是要找到 bug ,还是找到变化,对应的结果可能是完全不同的。我们的目标是,**即使找不到 bug,依然可以做好故障恢复**。 这样的思维惯性有多么普遍呢?我们举个例子:你是否曾在下班回家的路上,被老板电话叫回公司,查找线上 bug ? 也许你会觉得这样做很合理,但听完这节课以后,希望你能够意识到这种做法的局限性:线上有 bug ,为什么需要研发立刻回公司?先回退就好了嘛。否则,研发现场写程序,压力也是挺大的。 更别提,一些团队还经常出现喜剧性的一幕:生产环境出现了问题,研发火急火燎地改了个版本,结果系统做不到秒级发布,单是发布就用了半个小时。好不容易上线了,还没来得及高兴,就发现了个新问题…… 我们必须不断强调并加深印象:**生产环境永远不允许调试问题,出现问题立刻回退,查问题要去测试环境**。 你可能会想,老乔啊,你这就有点纸上谈兵了,很多大型发布涉及多个系统,怎么可能随便回退呢? 其实这个问题,亚马逊在十几年前就给出解决方案了:**大版本立项,小版本上线** —— 梳理好各模块的依赖关系,将各个系统、各个服务独立发布。当然,这也需要依赖服务版本化和 CI 能力的支持。 以上我们讲的是对企业系统的监控。除此之外,我们也要做好对企业业务的监控。 也就是说,对于企业任何一个未处于理想状态的业务环节,都要进行监控:做好问题的可视化展现、明确管理执行动作,通过数据化管理,不断完善企业的运营效率和运营质量。道理其实还是相通的。 如果能做到监视一切,分析一切,控制一切,“眼”能看见所有,“脑”能洞察一切,“手”能一手遮天,一切业务数字化,一切数据可视化,一切控制可触发,那么,这个企业的数字化水平一定已经很高了。 ## 结语 今天,我们从一个实际案例出发,主要聊了聊关于企业生产环境系统监控的认知和方法:**监控的目的是让系统一直处于健康状态,具体手段则可分为“监视”和“控制”两种;要做好控制,一个重要的方法是做好流控和版本回退。因为在大部分情况下,消除变化就等于消除异常。** 实际上,不单是技术、业务系统需要做好监控,研发管理、团队管理都要做好监控。 关于研发管理,我们在“高可用设计”部分曾提到:风险是经由开发环境、SIT 环境、压测环境、PRE 环境,进入生产环境的。所以我们要做的是严格检查各个环境下的异常。所谓研发管理规范,应该为代码版本进入下一个环境设置准入标准。对于任何异常,都有负责人进行修正。 对于团队管理,我们常常说,组织是结果导向的,但管理工作是过程导向的。关注过程自然就会得到好的结果,只盯着结果往往什么也得不到。对于一个项目、一个产品,乃至于团队的健康度,管理者有没有在关键节点设置监控?有没有针对异常做好控制?其差别是巨大的。 如果你认真学习了前面的内容,可能也会发现,无论是管理还是专业技术,很多关键认知都是相通的。很多时候,是“一理通百理明”。在学习的同时,前后交叉思考,也有助于你在更高的维度上掌握这些知识。 今天,我们就聊到这里,下一讲再见。