********本文是BLUES【公众号ID:bluemidou】向老王约稿,特授权blues独家首发,现转载如此,哈哈********
携程事件的官方解释:5月29日1:30分,经携程技术排查,确认此次事件是由于员工错误操作导致。由于携程涉及的业务、应用及服务繁多,验证应用与服务之间的功能是否正常运行,花了较长时间。携程官方网站及APP已于28日23:29全面恢复正常。对用户造成的不便,携程再次深表歉意。
当我看到这个故障结论的时候,我第一个感觉这是一个运维债务的问题,其次我会去想这个故障报告的措施部分怎么写,因此就有了最佳实践的描述,本文完全遵循该思路。
在之前我写了一篇文章【墨菲定律是运维的魔咒】,只要是概率大于零的事件,就有可能发生,支付宝的光缆挖断(具体内部原因不说)、携程的误操作还有我当时的故障经历等都是小概率事件。每个运维人不需要去庆幸这个事情没发生在我们身上,而是思考该如何避免发生?5.28事件应该是给所有技术人员,包括运维人员,甚至是业务部门提了个醒,是该重视运维的时候了,不要把运维当做成本部门来看待,他们一直在为业务产生价值。之后InfoQ高级运维群和其他人也针对该事件,纷纷表达了各自的意见:
- 阿里智锦认为运维应该从黑盒运维走向白盒运维,是一个转型的最佳时机。
- 移动王晓征则传递了他在移动核心系统方面的经验,核心系统频繁的真实切换演练,确保故障能够快速恢复。
- 做docker的同学则说,这个时候应该去拥抱docker,可以解决这个问题。
- 做数据的同学,也表达了数据备份多么重要。
我想在此基础上进一步去谈5.28的问题,虽然看起来是某个人为错误操作导致,但深挖下去能够琢磨出很多深层次的原因。如同Martin Fowler所说的技术债务一样,我把此问题归结为【运维债务】,既然是债,迟早都是要还的。那到底什么叫运维债务?运维为追求短期效应(如效率)而选择一个易于实现(如批量脚本)的方案,而没有进行全面衡量和考虑(比如说安全、质量),从长期来看,埋下了消极的隐患(债务)。到底是什么产生了运维债务?运维债务来自于两个方面,技术部门一味的满足业务功能需求、忽略运维需求,匆忙的架构设计,技术无统一规划等等;其次运维部门自身缺乏对技术的全面管理能力而带来的。因此任何谋求从某一个点上去彻底解决这个问题,我觉得都是欠缺的,需要整体性的思考和看待,整体的来看各个方面存在哪些运维债务,然后提出改进方案,才能更有效的规避这个问题再次发生。
一、流程和规范
5.28事件是因为一次误操作而起,但我还是相信这个变更行为是计划中,并且的确是涉及全网变更的。如果是全网变更,一定要引入相应的变更流程,确保有相应的审核机制。并且在缺少平台支撑的情况下,这种流程更需要实现和遵守。在后续就需要把流程实现在运维平台之中,和事务执行跟流程结合在一起。流程引入的一个好处,就是加强大家对变更的重视,提升质量意识。
1.运维债务
- 运维缺少变更流程和规范,分重大变更、日常变更等等,并且也缺少变更的事件窗要求
- 运维在没有平台的情况下,对于变更流程的线上化支持
- 运维缺少对重大变更的审核和check机制
- 运维缺少环境管理规范,明确环境管理的角色、权限、安全区域要求等等
2.最佳实践:
- 运维建立了很多日常场景的运维流程规范,比如说发布流程、交换机割接流程等等
- 运维在线上实现了某类变更场景的流程化和事务化的对接封装,比如说业务扩容流程、应用发布流程
- 对于涉及全网的重大变更,运维建立了相应的审核和double-check机制
- 运维制定了清晰的环境管理标准和分类,并制定相应的角色、权限和安全区域的管理要求
- 运维制定了清晰的服务部署规范,确保现网的服务部署都是标准化,包括所在目录、禁止root启动、普通用户属主等等
二、工具和平台
如果5.28的事件,是运维人员通过批量脚本变更产生的问题,这个问题可以简单一些,必须铲掉那个中控机器,并且严格要求以后禁止使用中控机器来对现网发起变更,和当时我们在腾讯所经历的一样,这种运维能力也就是智锦所说的黑盒运维能力。中控机铲除之后,接下来都会面临一个共性的问题,建立的工具平台如何避免人误操作?此时可以把工具平台的问题分成两个方面,第一工具设计开始是否考虑了对人误操作的保护,避免提供粗粒度的操作能力,提供灰度机制来保护操作,第二,当变更事务失败的时候,是否有回滚能力来保证刚才的操作可回滚的。
第一个工具的灰度能力很容易实现,特别是在可视化工具平台里面建立相应灰度发布机制,轻松容易实现。
第二个工具如何提供回滚的能力,对于应用级的变更来说,回滚能力是核心能力之一,这个时候就依赖于一个完整的版本管理历史,从而方便快速回滚。对于系统层面的变更来说,我们往往会忽视对历史变更记录的保存。所有国外的人把puppet称之为配置管理,它会对所有的配置管理都建立基线和版本管理机制,确保每个操作都是可以回滚的。
回滚有时候还要依赖一份基础信息,那就是服务器上的配置信息库,这个时候可以发挥CMDB的作用,让CMDB管理服务器上的应用状况。
1.运维债务
- 运维使用黑盒式的中控机来做变更,缺少对运维的可视化控制
- 运维自己认为效率优先,拒绝引入新的工具平台或者使用工具来做变更控制
- 缺少对开源配置管理工具的权限约束,带来变更隐患
- 运维的基准配置信息是没有在CMDB统一集中管理的。当某个服务器异常的时候,此时根本没法追溯上面的服务信息
- 运维的变更工具没有增加灰度能力控制
- 运维的变更工具没有提供回滚能力控制
- 运维的应用包没有建立统一的版本库,当出现故障的时候需要重新构建
- 运维的变更控制机的权限是和生成环境在一起的,并且是直接命令通道控制的
2.最佳实践
- 严格禁止使用某台中控机器来做运维变更机器,脚本批量的行为很难控制
- 提供标准化的应用管理规范,并基于这个规范建设相应的应用管理平台。工具从来都是建立在规范之上,否则就是一个ssh能力的封装。
- 在开源工具上,提供面向业务维度的管理能力,这个业务信息可以在CMDB中统一管理。
- 建立统一的应用发布平台,该平台提供统一的应用包管理、配置管理的生命周期管理能力
- 建立统一的应用发布平台,该平台提供标准化的灰度和回滚的发布能力
- 建立统一的应用发布平台,该平台提供所有的版本基线集中管理,达到一个程序可以四处运行的要求
- CMDB应承担维护服务器上应用信息、OS信息的职责,但问题发生的时候,可以借助CMDB的管理能力,快速恢复业务
- 严格禁止运维发布机器和生产机器同网络区域,安全问题
三、安全之权限管理
5.28所暴露出来的一个核心问题就是安全问题,更精确的说是权限管理的问题,一个运维人员拥有那么大的权限对现网发起那么大规模的变更实在有点不合理。
当年进YY的时候,第一件事就是提D/O分离,当时从安全的角度讲了D/O分离的必要性,当我们提D/O分离的时候,要做权限回收,很多研发就说会影响效率。因为当时的情况是研发主导变更,所有的变更脚本都是研发写的。我们当时承诺给建立变更平台来解决效率问题。后来就实现一套完整的应用部署平台,覆盖了YY语音所有业务的部署,并且花了一个Q的情况下,强制业务接入,最终隔绝了开发人员直接登陆服务器操作的过程。
就这个事件本身来说,从支言片语中,我没法去识别具体误操作影响范围,因此也就没法知道具体的权限管理问题。从我个人来说,隔离这种操作影响,把权限管理分成几个方面:
- 安全区域。
根据不同的用户对象,服务属性和管控要求设定不同的安全区域。从管理对象来说,比如说要设置开发、测试、生产、构建区域等等,这些区域之间的权限彼此隔离,严格禁止SSH互通。
到生产环境,此时根据实际的管控需要,建立核心数据管理区域,对于核心重要的数据集中存放管理。
为了适应发布和变更的需要,需要建立一个发布中控机器,在发布区域构建一个命令和文件下发通道,能够直达到开发、测试、生产和构建服务器等区域,从而建立起版本在各个环境之间的流转。
- 运维生产准入机制。
运维到达生产环境必须是经过明确的实名授权的,无论是LDAP还是堡垒机机制等等,都确保运维的后续操作可追踪和回放。
- OS操作系统权限。
root登陆权限必须回收(破坏力太大),禁止ssh直接登陆,其次开发应用运行用户权限和只读用户权限(日志查看的需要)。
- 应用系统权限。
应用系统运行的属主必须在普通用户下,进一步降低用户对root权限的需求,这属主的权限只能对有限目录开放,禁止权限放大后带来的破坏性后果。
1.运维债务
- 没有设置有效的安全区域划分,比如说开发区域、测试区域、生产区域、运维操作区域、代码管理区域等等
- 相同服务器存在多种维护角色,比如说开发、系统运维、应用运维、DBA等等
- DO之间和OO之间的职责定义都非常不清晰,导致相同的运维对象多人拥有权限
- 运维的网络接入没有设定准入机制
- 运维的操作接入没有设定准入机制
- 系统运维的权限过大,对所有设备拥有变更权限。通常使用puppet工具就可以得到
- 系统开放了root登陆方式,导致运维为了方便通过root方式登陆,再切换其他用户
- 应用程序运行在root之下,没有切换到普通用户属主,这个时候必须要用户有root权限
- 应用程序的运行目录是随意的,导致运维需要一个更大的权限去管理应用
2.最佳实践
- 运维的环境区域必须要进行隔离,开发、测试、生产区域不能ssh互通,并且严格禁止生产环境直接访问其他环境
- 禁止一个服务产生多个角色管理需要,比如说应用运维和DBA,此时必须做业务分离
- 运维的设备必须有准入机制,避免无名设备接入运维网络
- 运维的操作接入必须实名制,禁止系统用户直接登陆系统
- 禁止root直接登陆的方式
- 禁止应用运行在root之下(个别服务除外)
- 禁止同服务器上的应用多用户部署,并且部署是随意的
- 禁止系统运维直接对服务进行变更操作,puppet必须提供面向业务维度的管理,确保OS的变更是能够权限控制的
四、灰度机制
我把这个问题单独拿出来说,是因为它太重要了,是腾讯【海量服务运营之道】中的一个篇章。从昨天的故障来看,操作人员应该是没有遵循灰度发布的过程,否则这个故障的影响是可控的。
灰度发布:发布过程不能一蹴而就,是一个逐步渐进式的过程。我把灰度的理解是有两种:一种是运维灰度,基于机器级别,运维的变更和业务的发布经常会使用到;另外一种是基于应用级别,可以基于一些用户的特性,比如说移动的用户、北京的用户才能使用新的功能,这个是应用控制的,非运维变更工具能控制。
可以说灰度是避免运维踩大坑的有效方式,特别是机器灰度。有些场景的确需要运维执行批量变更,而这种变更如果不用灰度过程控制,不可预知的变更后果会覆盖到全网,造成的后果没法预估。
1.运维债务
- 运维把效率永远放在第一位,而缺少对工具的控制力
- 在中控机上使用批量脚本来对远程机器进行操作
- 工具平台没有实现灰度的机制
- 运维人员没有灰度发布的意识
2.最佳实践
- 对于即将要做的运维变更,最好先能够在测试环境进行。
- 测试环境测试通过后,先在非核心业务上进行,视具体的变更情况而定,设定一个观察周期。
- 非核心业务上灰度变更通过后,变更到所有非核心业务上,设定一个观察周期。
- 在非核心业务上变更完成后,在核心业务机器上灰度部分,设定一个观察周期。
- 确认以上的灰度过程没有问题之后,再灰度到全网。这个时候可以设定多步的灰度策略。
- 对于运维侧的灰度变更,一定要有平台来控制,避免这种灰度是人的行为.比如说puppet
对于业务服务的变更:
- 首先是运维灰度,在机器级先灰度部分机器,确认功能是否正常,如果正常的情况下,再覆盖更多的机器。严格禁止一次所有设备!
- 其次是应用灰度,这个视产品的要求而定,不在运维侧控制。
- 灰度发布的过程一定要有发布系统来控制,避免这种灰度是人的行为。
- 灰度需要作为一个运维要求,培训、宣传,确保大家一致理解
五、意识
意识是一个主观的东西,但是是可以被影响到的。其实在早期腾讯的运维经历中,也遇到过这类问题,之后我们不断去形成制度、规范、培训去影响大家的意识,最终其实是让运维对自己的操作形成敬畏之心。记得前不久还有一篇分享讲【对运维操作要有敬畏之心】,其中里面也是讲到微软公有云Azure的一次变更的故障分析过程。但目前互联网运维团队的一个现实情况是:新人的加入和不同企业背景的人加入,会让这种操作敬畏之心被稀释掉。另外互联网的生产环境是最容易触达的,也一定程度上忽略了对它的重视。不像银行,登陆到业务系统需要经过层层控制,堡垒机、单独的操作区、操作审核等等,一定程度上会影响你的操作行为。但我也不建议因噎废食,还是要勇敢前行。
前几天也有朋友说线上有人把rm -rf 目录/*写成了 rm -rf 目录 /*,在目录后多增加了一个空格,结果就把系统干掉了,这种经历在每个公司都碰到过。问我解决方法,我说良好的编程习惯和意识更重要,而非技术手段。一般我们会先cd 到那个目录,然后再删除,类似:cd 目录 && rm -rf *。
一个系统管理员根本没法评估它的一个命令在服务器上产生的影响,因此会产生盲点,忽视了操作带来的后果。另外环境分离之后,我们会逐步缩小SA管理的范围,到最后其实根本不需要专职SA。在之前所在的腾讯部门,根本就没有专职的SA存在,其次业务也逐渐降低了在系统管理上的依赖,最后内核参数的调优都交给了应用上线初始化的时候完成。
1.运维债务
- 运维的流程、规范、灰度制度还是停留在纸面上,没有转换成真正的运维理解。
- 运维的质量意识没有周期性的宣导,使得运维质量意识变得单薄,这个必须全员参与。
- 运维没有对新人建立起统一的培训机制,帮他们构建起业务质量的意识。
- 运维没有让新人接触生产环境是一个逐步的过程,比如说先自己构建环境,然后接管少量非核心业务,然后才是核心业务
- 运维新人接手工作是没有在老员工的指导下进行的
2.最佳实践
- 增加新人培训课程,里面分最佳实践、技能等方面的培训。
- 增加新人上岗前的考试,考试内容可以设计一些意识层面的题目,通过之后,方可上岗。
- 增加最佳shell编程实践的培训,形成良好的编程习惯。
- 强调对高危指令的谨慎使用,比如说rm、netstat等等。
- 建立新人导师制,确保新人接手运维的过程是在资深运维指导下进行的。
六、环境管理
5.28也暴露出环境管理的问题,为什么一个人的权限可以那么大,能够对所有环境进行操作?因此环境的混乱管理带来的是职责不清和安全的问题。
从持续集成的过程分类,你可以分编译、开发、测试和生产环境;从业务架构来说,环境分为:前端程序环境、数据库环境、分布式文件存储环境等等。从持续集成的环境来看,职责很容易界定出来。但是对于线上环境来说,严格禁止环境的混合部署,这个地方很容易出现的声音是分离部署带来的成本提升。不要关注这一点,成本和业务安全和技术架构优化相比,实在算不了什么。
1.运维债务
- 编译、测试、生产等环境的管理权限是没有明确界定,导致管理是模糊的。
- 测试环境是和生产环境是放在同一个网络区域,没有做权限隔离的。
- 开发环境和测试环境,甚至和生产环境是放在同一个网络区域的,没有做权限隔离。
- 数据层环境和其他服务环境是混合部署的,导致不同的运维角色对同一个机器有了共同的权限。
- 把成本作为环境分离的挡箭牌,带来的隐患是安全的问题。
2.最佳实践
- 禁止应用运维人员直接管理开发、测试环境,开发环境由开发管理、测试环境由测试管理。
- 编译环境可以由运维或者测试人员来管理,禁止开发人员管理,一个稳定的编译环境需要由一个专职团队来保证。
- 严格禁止配置管理工具接管所有的生产环境机器,特别是数据库服务器。
- 禁止环境复用,比如说web服务和DB服务,如果出现这种情况,这个服务器可以由DBA负责,而不能让应用运维负责。腾讯早期分离实践就是这么干的,可以大大提高分离的效率。
- 尽量不要用成本的原则来对服务器提出复用要求,更好的复用应该是在前端之间、数据库之间。同类技术服务,能够控制复用带来的风险。
- 环境最好有持续发布工具管理起来。
七、数据管理
对运维来说,数据分成两类数据:线上数据管理和运维侧管理数据。数据管理的核心目标是在正常保证服务的情况下确保数据安全,同时为服务异常时提供恢复保障。线上数据管理,往往运维部建立了各类规范和要求,比如说容灾的要求,备份的要求等等,就不说运维,研发也会提相应的需求给到运维。而对于运维自身平台的数据管理,往往就忽略了。如果运维数据的备份、容灾策略没有建设完备的话,运维平台的故障会影响线上服务的恢复效率,甚至是直接影响到服务是否能够恢复。5.28外部传言是删除了数据,我相信这个应该不大可能,因为我一直觉得DBA是非常专业的,一般都会本地备份,然后远程使用hadoop平台备份。其次从权限管理的角度来说,一般DBA的设备是不允许其他人直接操作,而DBA自身很少有批量的指令发到操作系统上,几乎无系统管理的需求。
1.运维债务
- 运维缺少对数据关联业务的重要性判断
- 运维缺少对管理的数据的重要性等级的一个划分和归类,比如说分一级核心、二级重要、三级不重要等等
- 运维缺少提供对以上不同等级的数据的管理策略,比如说备份策略、容灾策略、恢复策略等等
- 运维的核心数据备份策略是单一的
- 运维的核心数据容灾策略是单一的,特别是只建立本地的简单主备
- 运维没有把自身平台的数据和线上服务同等重要来看待,比如说CMDB、持续部署平台、仓库等等
- 运维没有把自身平台的数据交给DBA统一管理
2.最佳实践
- 运维数据和线上业务数据一样重要,其数据管理最好交给DBA统一管理。
- 对数据进行分级,建立核心数据和非核心数据的机制。这个需要业务配合改造才行。
- 对于核心数据,需要建立核心数据的保护原则,比如说热备、本地备份、异地备份等等
- 对于核心数据来说,必须要有本地热备和异地热备,确保数据库有切换的能力
- 对于核心数据的备份来说,需要建立多份备份,比如说用HDFS做数据库的备份,减少磁盘故障的依赖。
- 对于核心数据来说,需要建立proxy的访问原则,屏蔽一些高危的数据库操作指令。
- DBA应该统一接管运维平台的数据管理,特别是对于运维研发缺少DBA的情况下。
八、应急机制
在核心的业务保障上面,需要有容灾演练机制,来确定制定的应急预案是否OK,这是对人、系统和流程的全面检验,越真实越好。
在出现重大故障的时候,一定要快速成立故障决策小组,一定要由核心leader组成,最好是总监级别,然后运维总监牵头负责事务的总体跟进,这个应急小组需要对整个故障的处理、跟进、信息周知、资源协调等负责。否则很容易形成等待,底下人不知道做什么,最后就陷入混乱,从而影响故障的时长。因此在真实进入实施之前,核心人员(不宜过多的人)在一起讨论恢复方案,方案确定之后,立马确定负责人,分头实施。
1.运维债务
- 运维内部根本就没有重大故障流程机制
- 运维缺少对核心业务的周期性的容灾演练,来验证人、工具、流程能力
- 运维缺少对核心业务的重大故障场景的识别,比如说机房级故障、核心交换机故障、主机级故障等等
2.最佳实践
- 需要有周期性进行系统演练的计划。
- 确定对外信息发布的原则,必须经过许可才能发布,避免信息的错误发布给公司带来影响,昨天携程这一点做的不是太好!
- 周期性的进行信息对上周知,确保上层实时的了解到相关的处理进展。最好10分钟一次。
- 在分头故障恢复小组中,大家需要定时的把信息汇总到应急决策小组。实时进度汇总,便于事务关联方进行下一步。比如说服务器OS恢复了,就可以做应用部署了。
- 应急决策小组需要周期性(5分钟)把汇总性的信息传递到下面的事务处理小组中,让大家知道整体进度。
- 应急决策小组需要根据实施方案确定提前预知关联团队的下一步工作计划。
- 应急决策小组需要根据处理过程中出现的一些突发情况,快速做出决策,确定方案。比如说服务器没法远程安装,此时就需要快速联系机房解决或者找备用机房解决。
- 突发故障消除后,应急决策小组,需要统一出一份故障分析报告,详细复盘,找到后续的优化方向。
九、架构
这个架构不能深入谈太多,这样会涉及到很多方面。从本质上说,架构的设计是有两个目标的,一个是可运维性;其次是业务的高可用。可运维性,就是架构是否具备可管理性、可移值性、可恢复性等等,而高可用,完全是一个分布式系统的要求,比如说无状态的要求、统一服务调度的要求、柔性可用、过载保护等等。就本次事件问题,我更多的聚焦在可管理性。
可管理性体现在运维对业务技术架构的管理能力上。糟糕的情况是业务研发设计的架构根本就不通知运维同学,从而让运维从一开始就缺少对架构的了解。另外没有设计清晰的分层架构,导致权限管理混乱,从而产生潜在的安全问题,因此会产生如下运维债务问题。
1.运维债务
- 运维缺少对业务的架构文档化能力(对于小的业务来说,必须如此),特别是核心业务
- 运维缺少对业务架构的自动化识别能力,导致技术架构的变化,运维无法知道,特别是核心业务
- 运维的架构没有设计分层,不同的服务层是混合部署的
2.最佳实践
- 架构是否有做分离,比如说前端web层、逻辑层和数据层
- 顺应以上的架构拆分,服务最好能独立设备部署,做到不同的权限管理分离
- 数据层的服务必须分离出来,严格禁止和业务机复用
- 对于核心业务来说,必须让架构文档化
- 对于一个频繁变更的架构,必须从配置文件层面上规范约束,确保有自动化的架构识别能力
其实这次故障可以说给我们所有人都提了个醒,如果我们出现误操作了怎么办?首先我们先看遗留多少运维债务,从多个方面来看自己需要改进的地方,文章也给出了我自己的一些最佳实践。