运维进化论:微盟“删库跑路”给我们的启示

作者:茹炳晟,软件质量和研发工程效能专家

事件背景

微盟是国内移动互联网营销引领者,中国最大的微信公众智能服务平台,基于微信为企业提供开发、运营、培训、推广一体化解决方案,帮助企业实现线上线下互通,社会化客户关系管理、移动电商、轻应用等。

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状态,在试图修复这个问题的过程中造成了删错库的误操作,最终造成很多项目代码不同程度的丢失。

之后,又陆陆续续发生了类似的事件,例如2017年华为误删广西移动数据,2018年顺丰高级工程师误删。

微盟的危机应对值得我们借鉴

微盟的这次删库事件,对很多行业用户造成了很大的影响,但是面对危机,微盟所表现出来的社会责任感是值得我们借鉴和学习的。面对突如其来的故障,微盟并没有试图掩盖真相,而是第一时间在其官网发表声明,解释事情的背后原因,并且明确告知了后阶段的恢复计划以及明确的时间节点。

要知道,微盟也是此次事件的最大受害者,在幕后,我们可以想象会有多少个运维人的不眠之夜。

多一些真诚,少一些套路,有问题一起扛,是面对此类危机最好的方法。如果你试图掩盖,盖不住了就撒谎,接着就像张宇唱的那样“用一个谎言圆一个谎言”,必然会让自己陷入更深层次的危机。危机之下,我们要的是公开的信息,这样才能减少公众的猜测,抵制黑公关,并获得大家的理解和支持。

为什么恢复时间这么长?

那接下来的问题就是,既然微盟已经在全力抢修,同时腾讯云也给予了极大的技术协助,那全面恢复的时间为什么还要这么久呢?

圈子外的同学可能觉得这个不应该很复杂,感觉不就是重装一下系统吗,数据库不是都应该有备份吗,直接恢复一下不就行了吗。其实事情远远要比你想的复杂得多。很多时候,人常常会有一个认知上的偏差,对于一个自己没有切身参与过的领域,我们会不自觉地对难度产生错误的判断。这种所谓的迷之自信,是很难克服的。

这样的例子很多,比如在看球赛的时候,有人就恨不得把电视砸了,总觉得某些球员怎么这么挫,但是真要是轮到你上场,你就能比他好吗。再比如兰州拉面,看起来也没什么难度嘛,来回几下子面就拉出来了,但要是换你上,你能拉出那碗面吗。

其实,熟悉现代软件架构和运维的同学一定知道,现在软件的架构以及部署是极其复杂的,尤其在微服务大行其道的今天,每个微服务本身就是一个集群,微服务和微服务之间还有各种依赖关系,同时每个微服务都有可能会和数据库打交道,光理清楚这些服务之间的依赖和配置就够大家受的了。

更何况这次的微盟事件不是一次局部的更新和发布,而是几乎整体架构的全局梳理,从这个意义上说,难度不亚于从头搭建整个系统,更何况是在如此巨大的业务压力和舆论压力之下。

再来看看数据库,根据目前官方的信息推测,这次的数据库应该是在生产环境的本地库发生了不可逆的删除,否则不可能会需要这么长的时间。假定本地生产库没了,那唯一的方法就是借助远程灾备的全量备份库来恢复,但这也会引发出一系列的问题,比如远程库容量大,需要大量的网络传输时间。

再比如,增量备份的完整性欠缺,另外,还会出现由于近期的数据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个为什么之后,漏油的根本原因才找到。所以对漏油事件的根本解决方案,其实是改变对采购部门的绩效考核标准,这样才能防止以后发生类似问题。

对于日常的运维工作也是如此,只有这样才能发现和定位那些未雨绸缪型的任务。

好了,我的分享就到这里。困难的路越走越简单,简单的路越走越困难,祝好运!

作者简介

茹炳晟,业界知名实战派软件质量和研发工程效能专家,中国商业联合会互联网应用技术委员会智库专家,畅销书《测试工程师全栈技术进阶与实践》的作者,InfoQ极客时间“软件测试52讲-从小工到专家的实战心法”的专栏作者。现任Dell EMC中国研发集团资深架构师,历任eBay中国研发中心测试基础架构技术负责人、HP软件中国研发中心资深架构师、性能测试专家、Alcatel-Lucent高级技术主管、Cisco中国研发中心资深工程师等职位,具有超过16年的软件研发经验和技术管理经验。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/311489.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

拦截器如何获取@requestbody_分布式系统中如何优雅地追踪日志(原理篇)

分布式系统中日志追踪需要考虑的几个点?需要一个全服务唯一的id,即traceId,如何保证?traceId如何在服务间传递?traceId如何在服务内部传递?traceId如何在多线程中传递?我们一一来解答&#xff1…

.NET Core开发实战(第11课:文件配置提供程序)--学习笔记

11 | 文件配置提供程序:自由选择配置的格式文件配置提供程序Microsoft.Extensions.Configuration.IniMicrosoft.Extensions.Configuration.JsonMicrosoft.Extensions.Configuration.NewtonsoftJsonMicrosoft.Extensions.Configuration.XmlMicrosoft.Extensions.Conf…

前端demo_【前端3分钟】Script Error产生的原因和解法

Script Error对于前端开发者相信都不陌生,而且由于没有具体错误堆栈和代码行列号,成为可能是最神秘的错误之一。下面介绍Script Error产生的原理和解决办法。1、Script Error是如何产生的跨域资源引用假如:abc.com 下的页面引用了属于 http:/…

基于Abp VNext框架设计 - Masstransit分布式消息

abp 通过IDistributedEventBus接口集成自IEventBus实现分布式事件消息的发布订阅。IEventBus在什么时机触发PublishAsync?当前UnitOfWork完成时,触发IEventBus的PublishAsync在没有事务环境下,同步调用IEventBus的PublishAsyncabp 默认实现基于RabbitMq…

16进制数用空格分开 tcp_面试时,你是否被问到过TCP/IP协议?

点击蓝字关注我们看到这句话,有没有感到很熟悉呀?相信很多人在面试的时候都被要求,很多人会觉得我们在实际开发中一般用不到这些知识,所以对这些东西不屑一顾。但是小编认为想要成为一个完美的网工,那么对这些基础知识必须要有一定…

直接使用汇编编写 .NET Standard 库

前言Common Language Runtime(CLR)是一个很强大的运行时,它接收 Common Intermediate Language(CIL) 的输入并最终产生机器代码并执行。CIL 在 CLR 上相当于 ASM 汇编代码的存在。CLR 之上的语言 C#、F#、VB.NET 等语言…

[蓝桥杯2016决赛]七星填数-next_permutation枚举

题目描述 如下图所示: 在七角星的14个节点上填入1~14 的数字,不重复,不遗漏。要求每条直线上的四个数字之和必须相等。 图中已经给出了3个数字。请计算其它位置要填充的数字,答案唯一。 填好后,请提交绿色节点的4个数…

系统蓝屏的几种姿势,确定不了解下么?

前言在 蓝屏(BSOD)转储设置,看本文就够了!这篇文章里比较详细的介绍了蓝屏转储设置。做好设置后,我们就可以在需要的时候使系统蓝屏了。本文介绍几种使系统蓝屏的办法,当然肯定还有其它办法,如果…

最长公共子串-dp

题目: 给定两个字符串,求出它们之间最长的相同子字符串的长度。 公共子串和公共子序列不同,公共子序列不要求连续,但公共子串必须是连续的。如: A “helloworld” B “loop” A和B的最长公共子序列是"loo",但最长公共子串是&quo…

智能对话引擎:两天快速打造疫情问答机器人

01微软AI技术开源知识库疫情机器人近一个月来,“新冠肺炎疫情”成了所有人的热点话题,抗击疫情的战役在全国紧张有序地进行着。随着全国各地的企业陆续复工,怎样防范、保护自己和家人成了当下每个人的焦点。为了配合奋战在一线的医护人员打赢…

数码管

题目背景 小明的单片机上面的LED显示屏坏掉了,于是他请你来为他修显示屏。 屏幕上可以显示0~9的数字,其中每个数字由7个小二极管组成,各个数字对应的表示方式如图所示: 题目描述 为了排除电路故障,现在你需要计算&am…

fh 幅频特性曲线怎么画fl_初学者怎么练习线条?教你如何画出流畅线条的技巧...

初学者怎么练习线条?怎样才能画出流畅线条?画出流畅线条有哪些技巧?想必这些问题都是绘画初学者们比较伤脑筋的问题,那么到底怎样才能画出流畅线条呢?今天灵猫课堂老师就在网络上收集整理了关于初学者怎么练习线条&…

.NET Core开发实战(第12课:配置变更监听)--学习笔记

12 | 配置变更监听:配置热更新能力的核心这一节讲解如何使用代码来监视配置变化并做出一些动作当我们需要追踪配置发生的变化,可以在变化发生时执行一些特定的操作配置主要提供了一个 GetReloadToken 方法,这就是跟踪配置的关键方法接着使用上…

ASP.NET Core Web API基于RESTFul APIs的集合结果过滤和分页

译者荐语:如何在RESTFul APIs中进行集合结果分页?还是用客户端来拼接链接地址么?原文来自互联网,由长沙DotNET技术社区【邹溪源】翻译。如译文侵犯您的版权,请联系小编,小编将在24小时内删除。在ASP.NET Co…

.net 微服务实践

l 前言本文记录了我的一次.net core 微服务架构实践经验,以及所用到的技术l 优点每个服务聚焦于一块业务,无论在开发阶段或是部署阶段都是独立的,更适合被各个小团队开发维护,团队对服务的整个生命周期负责,工作在独…

redis过期监听性能_基于Redis的延迟处理

延迟处理是一个非常常用的一个功能;例如, 下单成功后,在30分钟内没有支付,自动取消订单;延迟队列便是延迟处理中最常见的实现方式;先一起看下JDK中延迟队列是如何实现的.JUC的DelayQueue在JDK中, 提供了一套延迟队列的实现, 是JUC包中DelayQueue类.在使用时只需要让处理的元素对…

【译】来看看WebWindow,一个跨平台的.NET Core webview 库

本文翻译自 ASP.NET 项目组的 Steve Sanderson 的博客,发表于 2019 年 11 月 18 日。Steve Sanderson 是 Blazor 最早的创造者。它类似于 Electron,但没有捆绑 Node.js 和 Chromium,也没有大部分 API。我的上一篇文章研究了如何用 web 渲染的…

sql if 和insert_拼多多面试:Mybatis是如何实现SQL语句复用功能的?

在工作中&#xff0c;往往有这样的需求&#xff0c;对于同一个sql条件查询&#xff0c;首先需要统计记录条数&#xff0c;用以计算pageCount&#xff0c;然后再对结果进行分页查询显示&#xff0c;看下面一个例子。<sql id"studentProperties"><!--sql片段-…

代码演示C#各版本新功能

代码演示C#各版本新功能C#各版本新功能其实都能在官网搜到&#xff0c;但很少有人整理在一起&#xff0c;并通过非常简短的代码将每个新特性演示出来。代码演示C#各版本新功能C# 2.0版 - 2005泛型分部类型匿名方法可以为null的值类型迭代器协变和逆变C# 3.0版 - 2007自动实现的…

《C++ Primer》1.52节练习

练习1.23 #include <iostream> #include "Sales_item.h"using namespace std;int main() {Sales_item trans1, trans2;cout << "请输入若干销售记录:" << endl;if (cin >> trans1) {int num 1;while (cin >> trans2)if (t…