事件背景
微盟是国内移动互联网营销引领者,中国最大的微信公众智能服务平台,基于微信为企业提供开发、运营、培训、推广一体化解决方案,帮助企业实现线上线下互通,社会化客户关系管理,移动电商,轻应用等。
2月23日19点,微盟出现了大规模系统故障,根据官方消息,这是一起运维部门核心员工在生产环境的“删库”操作引发的。截止发稿时,系统目前还处于修复阶段,预计全部恢复将在2月28日晚上24点完成。在这期间,微盟启动紧急响应机制,并在腾讯云的大力支持下一起研究制定生产环境和数据修复方案。
历史上类似的事件
说到“删库跑路”这档子事,历史上可以追溯到《西游记》,你是否还记得孙悟空大闹地府,硬生生把阎王爷的“地狱数据库”(Hell-DBMS),其实就是生死簿,改的面目全非的故事吧。
话说那孙猴子拿起大笔就把自己的名字,还有他的那些猴孙们的名字一起划了,以此避免了生老病死的轮回。很显然,这个地狱数据库显然是没有做过任何备份,从头到尾就那么一份,删了之后就再也回不去了。当然,这个只是我的一个玩笑,但是由此可见备份以及在系统故障情况下恢复能力的重要性。
IT历史上此类事件其实不在少数,2015年5月28日中午11时左右,携程官网和APP同时崩溃,一时之间,携程数据库被物理删除的说法在网上盛传,直到深夜23:29,携程才逐渐恢复。第二天,携程发布官方解释,称是由于运维员工的错误操作,删除了生产服务器上的执行代码导致,最终的详细报告官方并没有公布。
另一个著名的事件是2017年2月,Gitlab.com数据库也出现了误删,当时由于遭受DDoS攻击造成staging 数据库(db2.staging)落后生产数据库(db1.cluster)4GB的数据,并且staging 数据库由于PostgreSQL的问题处于hang状态,在试图修复这个问题的过程中造成了删错库的误操作,最终造成很多项目代码不同程度的丢失。
之后,又陆陆续续发生了顺丰,广西移动等类似的事件。
微盟的危机应对值得我们借鉴
面对微盟的这次删库事件,对很多行业用户造成了很大的影响,但是面对危机,微盟所表现出来的社会责任感是值得我们借鉴和学习的。面对突如其来的故障,微盟并没有试图掩盖真相,而是第一时间在其官方发表声明,解释事情的背后原因,并且明确告知了后阶段的恢复计划已经明确的时间节点。
要知道,微盟也是此次事件的最大受害者,在幕后,我们可以想象会有多少个我们运维人的不眠之夜。在这期间,腾讯云给予了极大的支持和帮助,派驻了很多一流的技术专家,不计成本来支持微盟和微盟的客户。
多一些真诚,少一些套路,有问题一起扛,是面对此类危机最好的方法。如果你试图掩盖,盖不住了就撒谎,接着就像张宇唱的那样“用一个谎言圆一个谎言”,必然会让自己陷入更深层次的危机。危机之下,我们要的是公开的信息,这样才能减少公众的猜测,抵制黑公关,并获得大家的理解和支持。
为什么恢复时间这么长
那接下来的问题就是,既然微盟已经在全力抢修,同时腾讯云也给予了极大的技术协助,那全面恢复的时间为什么还要这么久呢?
圈子外的同学可能觉得这个不应该很复杂,感觉不就是重装一下系统吗,数据库不是都应该有备份吗,直接恢复一下不就行了吗。其实事情远远要比你想的要复杂得多。很多时候,人常常会有一个认知上的偏差,对于一个自己没有切身参与过的领域,我们会不自觉地对难度产生错误的判断。这种所谓的迷之自信,是很难克服的。
这样的例子很多,比如在看球赛的时候,有人就恨不得把电视砸了,总觉得某些球员怎么这么挫,但是真要是轮到你上场,你就能比他好吗。再比如兰州拉面,看起来也没什么难度吗,来回几下子面就拉出来了,但要是换你上,你能拉出那碗面吗。
其实,熟悉现代软件架构和运维的同学一定知道,现在软件的架构以及部署是及其复杂的,尤其在微服务大行其道的今天,每个微服务本身一个集群,微服务和微服务之间还有各种依赖关系,同时每个微服务都有可能会和数据库打交道,光理清楚这些服务之间的依赖和配置就够大家受得了。更何况这次的微盟事件不是一次局部的更新和发布,而是几乎整体架构的全局梳理,从这个意义上说,难度不亚于从头搭建整个系统,更何况是在如此巨大的业务压力和舆论压力之下。
再来看看数据库,根据目前官方的信息推测,这次的数据库应该是在生产环境的本地库发生了不可逆的删除,否则不可能会需要这么长的时间。假定本地生产库没了,那唯一的方法就是借助远程灾备的全量备份库来恢复,但这也会引发出一系列的问题,比如远程库容量大,需要大量的网络传输时间,再比如,增量备份的完整性欠缺,另外,还会出现由于近期的数据Scheme变更引发的备份数据兼容性问题等等。这些都需要研发人员和运维人员的共同推进,这就会需要更多的时间。
运维进化的冷思考
通过这次的事件,站在运维的全局视角来看,对我们又有哪些启发呢。这里我提出了4个问题作为我们讨论的主线。
问题1:一个普通个体,能在多大程度上破坏系统?
先说我的观点:在信息时代,一个普通人完全可以摧毁一个系统。是的,你没有听错。这种事情在信息时代以前,是很难想象的。在人类历史上,一个个体决定一个民族,一个朝代历史走向的事情,也不是没有发生过,但必须是那些位高权重的大人物,你有没有听过,两个普通人聊着聊着,就把人类文明和外星文明都改写的事吧。
听起来很荒唐,但是这样的事情就发生在了刘慈欣的《三体》小说中,地球人叶文洁和三体人1379都是各自世界中的小人物,叶文洁处于对人类的失望,1379处于对生活的失望,在双方建立了联系后改变了人类世界与三体世界在接下来几百年中的命运。虽然这只是小说中所描绘的场景,但是所有的逻辑都是自洽的,就连霍金在接受采访时也表达了相同的观点。
回到运维和 DevOps,你有没有发现,现在很多互联网产品运维人员的权限其实是很大的,有时候大到可以直接摧毁一个系统,这种现象在一些B轮或者C轮的企业中尤为普遍,我们先不谈运维人员是否会处于恶意故意破坏自己的系统,但是忙着中出错的概率还是不小的。Gitlab.com的删库其实就是运维人员的误操作导致的,由于过多的终端窗口反复切换,导致原本应该在staging上执行的删库操作实际发生在了生产环境,最终酿成大祸。
所以,这个问题带给我们的启示是,要充分重视个人在系统中可能产生的作用,必须对个人的行为进行严格的监管,避免由个人引发的系统性故障。这也就是为什么大型企业都会建立比较完善的分级和分层发布流程,层层监管和审批,避免个人单点故障的无限放大。当然,这些监管和审批必须要纳入到由技术驱动的DevOps流水线中来完成,而不是靠传统的领导签字来完成。
问题2:“人肉运维”还有多大的生存空间?
首先解释一下“人肉运维”,我认为那些在生产环境中直接敲命令来完成的各种运维操作都属于人肉运维的范畴。我记得左耳朵耗子就说过“一个公司的运维能力的强弱和你在生产环境敲命令的多少成正比”,运维能力越弱,在生产环境上直接执行各种命令的频次就越高,运维能力越强,人直接和生产环境打交道的机会就越少。
所有对生产环境的变更,无论是系统参数、安全策略、网络配置、应用参数、环境参数、文件更新、数据库更新都应该是通过DevOps的流水线走正式的发布上线流程,所有的操作必须是由脚本或者自动化代码来完成,任何个人都不应具有直接在生产环境上执行命名操作的场景。这样做的好处有一下几点:
- 发布流程的详细过程可以被记录和回溯;
- 发布流程可以被重复,避免操作步骤的遗漏或错误,保证集群中节点状态的一致性,这点对于集群扩容场景非常重要;
- 避免生产环境中有人为产生的随机错误;
所以,这个问题的结论显而易见,我们应该尽可能避免任何形式的人肉运维,我们的行为准则是“人管代码,代码管机器”,而不是“人直接管机器”。
问题3:运维已经积累了大量实践,为什么依旧举步维艰?
随着软件架构复杂性的不断提升,运维的理念和技术手段也在一直都在不停的演进,从早期的运维,到现在的DevOps,再到日渐完善的AIOps,我们已经积累了大量的经验和最佳实践,但是为什么似乎我们运维人依旧感觉举步维艰。
我认为其中的原因有两个,一个是现在软件架构的发展速度在某种程度上超越了运维自身的发展。你如果回头看一下,运维的技术体系一直在进步,各种CI/CD的工具链,容器技术,自动化部署工具,系统监控方案都在日趋成熟,我们的运维能力的确在不断增强。但是,与此同时,运维的对象也随之变得越来越复杂,无论是依赖关系,还是集群规模都比以往任何时候都复杂,可以说“水涨船高”是现代运维所面临的主要矛盾。
另一个原因是,很多运维的最佳实践在实际工作中被“教条化”了,没有达到这些实践设计的初衷。比如为了防止人为的出错,在做一些关键操作的时候,我们往往会有Peer机制(两个人配对相互检查),也会有Checklist机制(自己检查),但是在实际执行过程中,往往是形式主义占了上风,这一点不用我解释你也能心领神会,所以这些机制并没有发挥出应该有的效果。因此我的建议是把这类方法完整嵌入到流水线的执行步骤中去,而不是靠人为的方式来实施。我常说一句话“凡是靠人完成的东西都是不靠谱的,要靠技术手段才靠谱”。
另外,还有一个我认为不太好的实践,在实际工作中为了引起运维工程师的注意,我们会把系统设计成“危机敏感型”的,也就是说有事没事都输出很多告警信息,或者很多一般的操作都让你反复确认是否要执行。比如,你发起某个命令执行某个操作,系统就会先给出告警,然后让你再次输入“Y”来确定是否继续执行,看起来这是一种风险更低和更稳妥的设计,但是实际上这会造成一定的困扰。
我们一定都听过“狼来了”的故事,当你每次都觉得这些信息是无关紧要的话,你就会下意识忽略这些信息,那么当真的狼来的时候,你就惨了。这个问题在以前的波音飞机的设计上也遇到过,因此我的建议是只在那些最有必要的操作上才启用这种双重确认的机制。
问题4:运维部门是成本中心吗?
在很多人的眼中,运维部门都被归在成本中心,简单来讲就是花钱的部门。运维是成本中心的宿命论对于运维的发展其实是很不利的。如果运维部门长期处于机械性的发布执行和生产环境救火的状态,那么就会陷入无止境的恶性循环。
很多时候,我们总是解决了看得见的问题,但是看不见的问题往往会在看不见的地方聚集,这类问题一旦出现就都是大问题。所以我们需要转变运维是成本中心的思维定式,让运维的同学能够更积极去思考和解决系统性的问题。
我们一直说有两种类型的待办事项,一种是既重要又紧急的事,也就是运维同学经常面对的各种救火型任务(生产环境Bug fix、Hotfix发布等),另一种是非常重要但是不紧急的事,也就是我常说的未雨绸缪型任务(自动化运维、监控数据分析统计、模型获取与优化等)。理想情况下,应该将更多的时间放在未雨绸缪型任务上,而只将少量的时间放在救火型任务。当把未雨绸缪型任务做好了,那么救火的概率就下降了。但是现实情况正好相反,运维同学天天忙于各种发布,各种线上救火,根本没有精力去偿还各个时期欠下的技术债,这种模式就难逃成本中心的宿命。
关于未雨绸缪型任务,我还想多说两点。
首先,运维部门有必要在平时定期开展一些故障演练的实践,结合混沌工程(Chaos Engineering)的思想,来确保系统的鲁棒性和可维护性,以此来应对各类突如其来的“黑天鹅”事件。这里我想强调“纸上得来终觉浅,绝知此事要躬行”,只有在实际故障演练的过程中,我们才有可能得到很多一手的宝贵实战经验,光靠想是不行的。
其次,对于日常运维中遇到的各类看得见的问题,不能只是关注表面上的解决,而是要有“刨根问底”的精神。这里我强烈推荐《丰田模式:精益制造的14项管理原则》一书中的方法:问N个为什么。
举个书中的例子,“工厂地上发现一大片油渍。通常的处理方式就是先清理地上的油,最多再检查一下,机器哪个部位漏油,换掉有问题的零件就好了。但是按照丰田的思路,会引导员工继续追问:为什么地上会有油?因为机器漏油了。为什么机器会漏油?因为一个零件老化,磨损严重,导致漏油。为什么零件会磨损严重?因为质量不好。
为什么要用质量不好的零件?因为采购成本低。为什么要控制采购成本?因为节省短期成本,是采购部门的绩效考核标准“。当你连续问了N个为什么之后,漏油的根本原因才找到。所以对漏油事件的根本解决方案,其实是改变对采购部门的绩效考核标准,这样才能防止以后发生类似问题。
对于日常的运维工作也是如此,只有这样才能发现和定位那些未雨绸缪型的任务。
好了,我的分享就到这里。困难的路越走越简单,简单的路越走越困难,祝好运!
作者简介:
茹炳晟,业界知名实战派软件质量和研发工程效能专家,中国商业联合会互联网应用技术委员会智库专家,畅销书《测试工程师全栈技术进阶与实践》的作者。
现任Dell EMC中国研发集团资深架构师,历任eBay中国研发中心测试基础架构技术负责人,HP软件中国研发中心资深架构师、性能测试专家,Alcatel-Lucent高级技术主管,Cisco中国研发中心资深工程师等职位,具有超过16年的软件研发经验和技术管理经验。