当前位置: 首页 > 科技观察

轻松应对上千节点故障,去哪儿网混沌工程自动演练实践

时间:2023-03-19 13:31:42 科技观察

一、混沌工程价值探讨因为混沌工程是一个比较新的技术,我们不可避免地会面临一个问题:当我们想要实现混沌工程,我们需要证明它的价值,然后决定我们需要投入的人力和想要的效果。作为科技行业的从业者,我们经常会了解到各大公司的宕机事件,比如去年韩国电信的网络崩溃,Facebook的服务器宕机等。大规模停机。大多数人看到这些新闻都是抱着吃瓜群众的心态,但是作为科技行业的从业者,这种问题可能有一天会发生在我们身上,出现在我们的机房和公司,我们需要去解决。1.去哪儿网系统组下面简单介绍一下去哪儿网系统组。目前在线运行的活跃应用3000+,提供18000+dubborpc服务接口、3500+http域名注册、13000+mq主题、公司内部5种语言的技术栈。基于Java和node,可见关系的复杂性。只要一个地方出了问题,就可能会级联到c端,用户端就会感觉到问题。那么我们应该如何管理这些系统群体呢?混沌工程是一个很好的方法,后面会介绍如何使用混沌工程来解决这些问题。2.常见故障原因在我八九年的从业生涯中,我们也遇到过大量的基础设施问题,比如微服务注册中心zookeeper经常抖动,消息队列问题,甚至机房断网断电。问题也可能出现。从故障原因来看,我们可以分为几类:底层机房、中间件、机器问题影响比较大。当机房挂掉时,整个机房的相关应用都会受到影响;整个拓扑都会存在依赖问题。不同的故障产生的原因是非常不同的。只有拉长时间线,我们才能发现它们之间的某些共同点。但是,短期内很难通过方法解决所有问题。混沌工程可以让它变被动为主动。混沌工程要解决的主要问题不是让软件不失效,而是软件在失效时是否仍然具有一定的恢复能力,是否还能提供优质的服务,是否能够主动构建故障并提前修复它们。因此,我认为混沌工程有两个目标:第一,通过混沌工程,我们可以建立系统抵抗生产环境失控情况的能力和信心,这就需要我们提前处理问题并产生相应的改进和计划。二是把不确定的事情变成确定的事情。其实,无论是质量,还是可靠性,还是稳定性,最可怕的不是我们能不能做什么,而是我们做完了永远不知道会不会出问题。3、混沌工程的好处我认为混沌工程可以有以下三个好处。1)每个人的不同角色,站在用户的角度,都能得到稳定的用户体验,不会因为技术问题导致用户体验差,甚至得不到服务;从测试的角度来看,可以减少甚至提前预防故障;从开发和运维的角度,可以提高应急响应的效率。2)过程将对一个乱序的具体问题具体分析的过程转化为系统治理的过程。3)系统从正确的设计转向了面向故障的设计,为整个系统提供了一定的弹性和容灾能力。对于一些基础能力,可观察性、灰度、回滚、可降级等不再是期望,而是实际可以获得的能力。2.去哪儿网混沌工程平台我们首先提出一个问题:混沌工程的最佳实践是什么?在业界大家经常看到的混沌工程,第一反应就是攻防演练,比如线上乱插乱拔,乱注入故障,但是我个人并不认同。混沌工程就是把不确定的问题变成确定的问题。虽然人为攻防也能在一定程度上解决这个问题,但是人为攻防需要投入大量的时间,而攻防所产生的知识是可以固化和扩展的。有限的,除非混沌工程的文化能够在整个公司从上到下彻底贯彻。从这个角度看,乱演不是我们的最终目的,那么我们的目的是什么?我觉得需要分成多阶段的目标,后面会根据我们实际的路线进行说明。重要的是要注意,功能支持并不等同于实践模型。目前,许多公司都在研究与混沌工程相关的系统,或提供相同的能力。但是我觉得这里面有个很大的偏差,提供能力不代表混沌工程的目的就达到了。因为从实践模型来看,覆盖率和效率是多少?接下来,我将详细解释我们的做法。从应用架构层面来看,基本上每个公司都没有多少偏差。底层是机房可用区,上层是中间件、服务器层、应用层、依赖层。级别越低,出现问题的概率越小。在业务管理中,经常出现超时熔断甚至限流的情况,但机房层面统一挂机或断电的概率要小得多。但底层失效概率小,冲击面却很大。应用架构的高低以及对应的故障情况,极大地影响着我们实践的节奏。要实现混沌工程的两个目标,不是一蹴而就的,这意味着我们要做很多工作来保证机制的制定和有效性。当我们划分在相应阶段投入的人力时,应用程序架构层次结构是一个很好的指南。当我们一无所有时,我们应该优先解决影响大的问题。如果服务之间的依赖关系做好了,但是机房挂了或者中间件挂了,整个服务不可用,一切都是笑话。所以,从实践路径出发,我觉得可以分为四个节奏:1)首先在机房、中间件、物理机、虚拟机层面做关机演练,尽量消除大面积的影响可能的。2)应用演练在于应用的可用性管理。3)依赖演练在于治理拓扑上合理的依赖。4)攻防演练解决人员面临失败时是否有相应的应急策略,以及应急策略实施的及时性和恢复时间。从左到右的路径实际上是一个逐渐缩小影响区域的过程。1.停机演练去哪儿网混沌工程平台建设的第一步就是对停机演练的支持。在容量目标上,我们要求同一机房一条业务线的所有业务节点挂掉时不受影响,所以我们可能需要上千个节点在一次演练中挂掉。要实现这样的能力,需要直接使用混沌工程的现代技术并不多,因为关机演练不是针对应用层面的,而是针对机器节点层面的。它的重点是基础信息的整合和全流程的打通。1)机房聚合信息查询,可以发现应用是否达标,即机房宕机时应用是否受到影响。影响有两方面,一是应用只部署在单机房,二是单机房宕机时其容量是否足够,提前改造应用。2)自动建立通讯组。如果整个执行周期很长,我们需要提前做好计划,对非常明显的问题进行改造,然后进行真正的执行进度公示和事后总结。以上所有过程都需要大量的自动化信息才能被知晓,我们在内部IM系统中有一套沟通和通知机制。3)真实关机,测试机器重启和应用重启的时间是否满足要求。如果只是假装失败,演练恢复速度快并不代表真正失败时速度足够快。4)接入告警,告警事件关联推送5)虚拟机上电后自动恢复关联服务我们的容量目标需要大量的节点故障,无法手动恢复,不能一一依赖人工当机房出现实际问题应用排查和恢复时,虚拟机开机后自动恢复关联服务的功能就显得非常关键。停机演练的实施有以下几点:管控维度:我们提供机房、应用、机房三个层次的筛选。技术观点:不涉及目前的chaosmesh或chaosblade等技术,更多的使用了云集群的原生技术,如openstackAPI或saltstack,以及自研的控制平面,包括刚才提到的control和drill,整理功能。停机演练效果:我们进行了49次机房演练。对覆盖的机器进行去重后,总共有4000+台机器,覆盖了500+个应用。基本上每次演练都能发现10+个问题。单机级别的停机演练,我们进行了71次,覆盖了3000+台机器,200+个应用。当我们进行真正的停机演练时,如果监控图出现异常,说明机房出现了问题,会影响到C端的业务,所以需要提前修复。主动发现问题,制定相应的修复方案,提前修复问题。2.应用演练应用演练的能力目标是对所有应用选择多策略故障注入,主要解决应用可用性问题。重点是:1)在线上环境做单应用可用性演练,因为线上环境、测试环境、演练环境是有区别的,包括服务治理参数和对应的配置,对服务的响应也不同不同的。如果你在测试环境下做得很好,可能会因为线上环境的配置不同导致演练的结果不对。2)可靠的注入工具因为我们需要将故障注入到非常核心的应用程序中,所以可靠的工具是我们的生命线。如果注入工具本身不可靠,很可能导致级联很多问题。3)丰富的排练策略4)有效面一定要可控,不能因为排练造成乱攻击,造成线上问题。首先要做的是对注射工具进行技术选择。我们云平台中的容器和虚拟机都需要支持,需要的场景也比较丰富。我们对开源的要求也比较高,因为需要二次开发。最终,我们在选型上选择了更合适的chaosblade。接下来对chaosblade做一个简单的介绍。Chaosblade支持很多场景,包括容器级别、操作系统级别和语言级别,比如Javaexecutor。以上是我们广泛使用的,特别是通过Java技术,我们对它做了很多改造。chaosblade的功能基本涵盖了我们日常常见的中间件场景。比如在应用服务层面,一般的rpc框架、网关、消息中心件对我们的覆盖面都比较广,尤其是数据库、缓存等都有一定的支持。Chaosblade的基础功能比较完备,但是在企业场景中存在一些不足,比如HTTP超时能力、fullGC、日志拥塞等。甚至官方都不支持区分同一接口不同调用点的依赖,以及全链路匹配。实现这些能力后,我们回馈给了官方,所以如果你现在使用最新版本的chaosblade,你就会有以上的企业场景。选择chaosblade后,我们需要在演练前做好准备。首先,选择其资源和策略。演练过程中自动挂载agent,然后通过选择的策略自动注入故障。通过流量复制的方式在手动触发和手动触发的情况下,在C端触发两部分进行验证。目前我们已经实现了全链路的场景匹配,可以区分用户的真实流量和测试人员的人工流量。在恢复阶段,我们有两种恢复方法。一是防止我们底线报警或者超时恢复。如果全部执行完都没有触发,则采用手动恢复,然后卸载agent。最后对问题进行总结改进,完成复习。以上是新建练习的效果图。您可以在练习中选择相应的应用、机器和策略,安排好后可以定时执行。3.依赖关系演练应用程序的可靠性不仅受应用程序本身的影响,还受其所依赖的信息服务的影响。当你维护所有应用的时候,你会想到:死友不是死穷,就是所有同行都可以出问题,而我不行。当我们保持这种心态来治理服务时,我们需要非常注意依赖性。被拖死、被影响、被传递时,如何解决依赖带来的蝴蝶效应;期望;而强依赖太多,能否降级为弱依赖,以上问题就很关键了。因此,依赖演练的能力目标是对应用层的外部依赖进行多策略演练,判断是强依赖还是弱依赖。依赖演练的要点是:1)做好应用元数据的收集工作。如果没有应用元数据的集合,就不可能知道应用的所有外部依赖。我们收集所有与rpc和服务注册、数据依赖、redis和一些定时任务相关的信息,并汇总通过日志暴露的元数据、注册中心、DB元数据或应用程序,甚至跟踪信息。产生了最完整的应用元数据。2)可视化的应用拓扑,方便我们观察谁调整了应用,我调整了谁,对于我们控制有效面非常有效。3)区分不同场景下的同一个依赖,也就是刚才说的同一个接口在不同调用点的依赖。4)标记强弱依赖对收集到的信息进行分析、聚合和存储,并在信息上标记强弱依赖。以上是强弱依赖标注的界面效果图。我们可以区分出很多很细的类型,对应的目标也很多。依赖演练有一个逻辑闭环:我们的服务治理收集完依赖后,需要让用户标记依赖,相当于知道了用户期望的依赖,然后我们进行强依赖和弱依赖演练,并得到钻孔结果进行修正。看是否符合用户预期,导致对比度差距。如果用户期望它是弱依赖,但实际在线执行是强依赖,那么我们可以生成我们改进的计划集并修复它。依赖演练效果:我们进行了1200+次演练,涉及3000+个依赖接口。我们在去年5月1日之前做的依赖演练发现了136个问题,问题类型不一致。比如弱依赖写成强依赖,还有配置问题,容量问题等等。4.平台架构关闭演练、应用演练、依赖演练完成后,我们的平台架构如上图。我们支持以下三种形式的资源层:物理机、虚拟机和容器。不同的操作有不同的手段。在钻头系统中,我们也有比较丰富的功能:钻头的生成,钻头的编排,以及相应的执行和标注。以上是应用管理平台和依赖信息平台,以及监控等APM等一些支持。3、大型自动演练虽然我们已经具备了对应大型自动演练的能力,但是当我们要做覆盖面非常大的演练时,我们需要思考一个问题:常态化演练的成本效益比是多少?合理的?如果只是假期演练或一年一两次演练,那么你需要权衡投资。我们在进行定期演练时,难免要考虑人工成本。前面说了,在演练的次数上,需要一定的人工参与,会消耗一些人工成本。当我们规范化的时候,我们必须考虑自动化,而自动化可以替代人工成本。另外,精品作品的性价比自然更高,因为精品作品不像创意作品,防御作品需要全面覆盖。如果每个点的性价比都不够高,那么整体的损失会非常大,这对我们来说是很大的。这是一个很好的指南。自动化的目标之一是持续的可靠性。我们想让它正常运行,进行自动演练,主要涉及两点:第一,我们希望它经常使用,常新,降低人工成本,最大限度地覆盖。这里的关键点是它使执行的流程和断言自动化。人类参与的目的是断言最终结果和制定具体方案。二是可用环境。我们把周期性的自动演练机制分为两类:增量演练,每天演练所有新的依赖。全面演练,设定一个循环重复。因为我们所有的代码和架构都在腐败的过程中,中间会有很多变化,比如调用点的代码变化,可能会导致强弱依赖关系发生转化,所以我们要定期验证.1.自动钻的流程我们的自动钻的流程如上图所示。第一步是制作控制面,可以获取应用信息。第二步是向其中注入故障。第三步,触发自动化测试,从而产生两个流量,分别发送到我们的基准环境和对应的测试环境。测试环境的代码配置和benchmark环境一样,然后自动化平台会对返回的结果进行断言,然后得出结论:当我注入这个问题的时候,流量是否还正常。自动化检测结果完成后,即可生成依赖判断。如果注入失败有问题,说明是强依赖。通过自动化演练流程和自动化测试平台的引入,我们可以做到无需人工触发流量和判断。2.练习总结从性能数据来看,有很多依赖不符合开发预期,远超大家的想象。在抽样中,达到了73%,而只有27%符合预期。主要问题包括强依赖不合理、单应用演练口径过严、自动化测试平台覆盖不足、无法全面上线等。如果单个应用程序通过接口自动化平台进行断言,可能会出现一个问题,即结论可能过于严格。比如A依赖B,再依赖C,对于B调整C,可能是强依赖,但不会传递到用户端,可能对用户端没有影响。只是局部强依赖,所以会放大。这个问题。所以我们考虑是否可以进行全链路演练,经过测试是可行的。3.全链路演练从信息来看,一个函数入口对应一个后续流程,流程中的强弱依赖非常复杂。可能存在完整的强依赖,也可能存在中间的强依赖。或者有的是纯粹的弱依赖,这些关系决定了我们的解决方案。与刚才提到的单应用断言不同,全链路断言需要引入全链路压测演练系统。我们内部有全链路压测平台,可以自动生成用例和隔离数据,执行成本非常低。比如机票业务线的所有核心场景可能只需要半天时间就可以执行完,相当于我们只需要0.5pd的人力就可以覆盖上千个应用。从断言的角度来看,我们有一个断言逻辑:当ingress产生调用流量的时候,我们会对其进行断言,观察我们的核心指标有没有问题,尤其是用户侧的核心指标。如果出现问题,我们将中断演练,并记录相应的结果;如果没有产生相应的告警,我们也会从另一个角度来看是否对C端的功能有其他影响。我们将人工标记的告警事件和系统自动分析的雷达事件统一起来,然后得出一个结论,即当全链路注入的问题是对入口的强依赖或者弱依赖时,这是一个断言逻辑。从流程上看,和刚才的自动钻取流程有些相似,只是将接口自动化测试平台改造成了全链路压测平台,但其断言逻辑与自动化断言的断言逻辑不同。需要注意的是,我们需要优化链接的命中率。命中率是指从入口发出的流量是否一定会通过我们要测试的依赖。比如我要测试系统e对系统g的调用,从入口发出的流量不一定能到达e的依赖链路。打b系统,然后打e系统,再打f系统,这就需要一个非常有效的机制来提前发现演练的流程和我们预期的依赖是否达到了。这需要依赖很多其他信息。如果我们不使用精确的方法而是随机选择入口流量,那么链路上的命中率只有40%左右。我们希望将命中率提高到90%以上。对于命中率我们做了一个精准的策略:使用依赖关系已经产生的实际数据,也就是线上APM的trace数据可以反推链接的请求情况和流量,比如当我们想找到e和f的调用链接时,可以从系统b的入口到系统e再到系统f。这是我们要查找的链接之一,然后反向给出结论,从而得到对应trace的入口信息,进而得到入口的入口信息。请求条件信息,通过请求条件自动构建用例,我们可以得到一些非常有效的用例,从而使我们的命中率提高到90%以上。从全链路自动演练的效果来看,目前覆盖了去哪儿网55家核心门户和80%以上的核心应用,只剩下最后的人工成本。只要对汇总报表进行最后的分析,就会产生假期。一份混沌工程报告就可以了。4、故障注入攻防演练第四阶段是故障注入攻防演练。攻防演练的主要目的是提高人们在面对失败情况时的处理速度,包括计划和问题。首先,很难通过每个系统的开发来积累处理故障情况的经验。因为一个开发真正能遇到线上失败的概率并不高,公司几百人的研发团队会稀释失败,人工经验很难积累,所以只能提前创造机会。只有面对线上的问题,才能给出解决方案。其次,故障原因种类繁多。三是没有计划。第四,恢复和验证难度加大。2020年我们排错时间的中位数是54分钟和39分钟,2021年也是51分钟,所以真正在线bug的处理时间还是比较长的。1.攻防演练流程我们设计了一个攻防演练流程:该流程依赖大量的基础设施系统,包括故障平台、混沌工程平台、监控告警平台、日志平台、Trace平台等。先规划攻击点,总结历史故障原因,将频繁出现的原因先规划为对应的攻击点;其次,故障是随机注入的,注入点和时间是随机的,不同接口依赖的开发没有提前通知;然后监控告警触发,防御方检查问题需要上报相应的结论、耗时等检查结果;最后对其应用一定的评分公式,进行评论分析。故障注入过程类似于全链路依赖过程。它只需要注入流量,不需要断言它的强弱依赖。从积分实例可以看出,大部分问题可以在1-3分钟内解决,通过这种方式演练可以有效提高排查问题和解决问题的速度。2.攻防演练要点1)培养混沌文化混沌工程应相应推进,发展非常关注攻防演练。2)时间和策略是随机的。3)消除信息干扰。比如注入的信息不能暴露在异常栈中,对应的chaosblade等关键字不能出现,还有一些流量标识也需要擦除。Q&AQ1:如何确定应用级容灾演练验证的范围?A1:应用级容灾需要多个可用区,保证每个应用不能只部署在一个可用区,在聚合信息时可以提前发现和修改。真正改造后的演练,就是分享中提到的机房大面积停机演练。从云平台的元信息中,可以轻松查询到某个业务线的所有应用实例,然后进行真正的关停演练。观察相应的核心业务指标。如果业务正常,则说明具备容灾和容量条件。对于验证范围,单应用演练只需在当前应用接口层面进行测试即可,方法有多种,如接口自动化测试、手动触发用例测试等。Q2:底层越低,故障影响越大。你用混沌工程解决过底层网络故障吗?A2:底层网络故障主要是通过大规模停机演练来代替,因为交换机和机器的网络通信故障并不是什么可怕的事情,问题点恢复后影响基本会自动恢复。如果确实需要排练网络问题,可以进行交换机拔出测试。Q3:混沌工程推广过程中如何衡量业务层面的需求?A3:在业务层面需要区分不同的角色:对于业务负责人来说,混沌工程的结果需要对业务有利,比如保证用户体验,保证业务的平稳运行;对于技术负责人来说,混沌工程可以提高人员处理线上问题的速度;对于QA等稳定性保障人员,混沌工程可以将不确定性转化为高度确定性。另外,如果问题中的需求是指混沌工程推广与业务项目之间的人为冲突,可以参考分享中的实践路径。事实上,机房关机演练、应用演练、依赖演练的人力资源并不多。攻防演练需要给予业务需求项目优惠。Q4:混沌工程针对关键系统的实验思路有何不同?A4:在我们的实践中,关键系统没有特殊处理,一切都要追求高效率、高覆盖。对于关键系统,也是真正的关机、真正的注入、真正的上线环境。