酷家乐自某次故障后开始升级演练平台,旨在提高系统在面对真实故障时的应急响应效率。面对业务线真实场景演练中高达39%的人工验证比例这一瓶颈,酷家乐构建了自动化流水线,设计了针对性的自动化用例,并选择了合适的自动化框架,确立了清晰的自动化流程。这些措施显著提升了自动验证效率,2023年第三季度演练次数超过100次,展现了自动化演练平台在提升系统稳定性和可靠性方面的显著成效。详细的解决策略和方法,请参阅文章正文。
作者介绍
TakinTalks稳定性社区专家团成员,酷家乐SRE负责人。专注 DevOps、混沌工程、故障诊断等领域。目前在酷家乐负责大规模落地混沌工程的实践,支撑业务用户各类故障演练场景及预案建设,在安全生产领域积累了丰富的经验。
温馨提醒:本文约6000字,预计花费10分钟阅读。
后台回复 “交流” 进入读者交流群;回复“Q105”获取课件;
酷家乐混沌工程的起点,可以追溯到2023年年初的一次线上应急响应。当时,我们的核心业务——设计工具遭遇了严重的故障,导致用户设计方案的保存和加载功能长时间失效。这次故障发生在业务高峰期,对我们的用户和业务造成了显著影响。在紧急情况下,我们采取了临时措施,包括将存储集群从腾讯云切换到阿里云的备用集群。然而,这一过程中我们发现备用集群同样面临压力过大的问题,这迫使我们对腾讯云的主集群进行扩容。直到傍晚,业务才得以恢复正常。这次经历虽然痛苦,但也为我们提供了宝贵的教训。我们意识到,尽管我们的应急响应方案具有一定的选择性思考,但在详尽的切换预案和演练流程方面仍显不足。这次事件成为了我们转变研发方式、强化混沌工程实践的一个重要契机。
酷家乐的混沌工程探索始于2020年,当时我们开始构建演练平台,引入了阿里在2019年开源的Chaosblade工具。这一时期的平台上开放的故障项较少,2021年的落地效果并未达到预期,演练模式和演练支持的资源类型都比较单一,因此实践规模较小。到了2023年,我们在故障后的应对中开始升级演练平台,引入自动化流水线,使故障注入与恢复的能力更稳定,除了容器类型故障之外,我们也扩展了物理机和虚拟机类型的故障。并且开放了突袭演练、强弱依赖演练、线上演练等几种模式。至2024年年初,我们进行了一轮核心业务的强弱依赖演练,部分业务已能在线环境中进行演练。1.2.1 挑战
1.2.2 应对策略
1)策略一:明确演练的目标和形式,探索多种演练模式
关于演练的目的,通常我们比较熟悉的是故障演练,然而,这仅仅是众多演练方法中的一种。演练的价值在于其能够带来的长远影响,而不仅仅是过程本身。因此,我们从两个维度对演练进行了深入分析。在形式上,分成引入故障和不引入故障两种手段;在目标上,我们参考了业内主流的、公司急需建设的几种演练场景,这些多样化的演练方式才能真正为在线服务带来积极的影响。2)策略二:扩展演练模式,基于故障注入强化依赖演练能力
a. 强弱依赖演练的模型
如下图所示,是我们监控系统中的一个依赖关系图,其中黄色部分代表某个特定接口。通过监控系统中的依赖关系图,清晰地识别出接口所依赖的下游服务,包括缓存和数据库。在复杂的软件系统中,任一组件在长时间内的可用性都不可能绝对达到100%,因此从整体上来看,整体100% 可用的目标的达成具有挑战性。为此,我们参考业内主流的强弱依赖模式,引入“依赖强度” 的概念,以评估我们所依赖的组件对系统整体可用性的影响。b. 依赖数据如何管理、依赖如何自动化验证
-
如何定义依赖:我们的定义包括了对于应用所需的所有容器实例、存储、配置中心、负载均衡网关等组件。
-
如何获取依赖信息:我们的监控系统相对完善,可以从接口层面获取所有下游依赖的信息,这些数据是通过历史调用数据和聚合分析得到的。
-
依赖信息的动态更新问题:我们通过版本控制的方式来处理。
-
关于依赖粒度问题:理论上我们可以精细到每一个数据库表或索引,甚至是每个API,但在实践中,我们发现过于细化会导致依赖项数量急剧增加,从而增加了验证工作量。考虑到这一点,以及实际故障情况很少仅由单个表或API引起,我们建议在选择依赖粒度时尽可能选择较大的粒度,这样不仅可以减少工作量,还能更接近实际故障场景。
我们针对依赖演练引入了接口测试的验证方式。依赖数据本质上是从每个 API 的依赖关系,验证的主体仍然是每一个 API,于是引入接口测试进行尝试。这部分我将在后文详细展开说明。3)策略三:扩展演练模式,基于小流量验证的线上演练模式
除了常用的依赖演练之外,我们还实施了线上演练模式。通过充分调研外部和业内公司的实践,我们发现基本大家的核心逻辑都是采用小容量验证方式,通过路由或其他流量控制手段,确保只有少部分流量经过有故障的服务,再与线上服务对比。图 – Netflix、AWS 等公司采取小流量验证的模式通过这样的策略来实现线上模式,结合公司现有基础设施形成一套流程模型。在正式环境中,全量流量演练前需要准备一套与线上环境完全一致的环境。接下来通过故障注入、预案执行或降级开关操作,让特殊环境的实验效果显现。最后,通过路由策略引导一小部分流量至特殊版本,模拟故障效果。通过小流量验证的优势是,在遇到紧急情况,如线上发现多个问题或不可控时,我们可以将流量切回正式环境,立即恢复故障。因此,线上模式需要一套流量路由控制策略和实现版本化小环境的能力。在紧急情况下,我们可以通过回切流量实现快速恢复,而不必依赖容器层面的自动恢复或降级开关关闭。我们还为线上业务线提供了指导模板,强调演练目的、预期表现等关键内容。预期的表现尤为重要,因为演练后需要观察效果是否达到预期。报告分为业务影响和用户影响两部分,重点评估影响范围。同时,风险评估也不可忽视,需提前考虑数据安全风险,并让业务线配合执行应对措施。图 – 一次线上演练和步骤说明的报告4)策略四:突袭演练方案优化
当时我们在使用Chaosblade进行故障演练时,主要依赖于客户端记录。然而,这种做法引出了一个问题:一旦故障注入后,业务线倾向于直接重启出现故障的实例,从而迅速恢复服务。这种简单直接的做法并未能充分锻炼团队执行预案的能力。我们对比了客户端注入和服务端注入两种策略,发现客户端注入的影响范围较小,且主要依赖于自身服务的权限。而服务端注入影响范围广泛,但其不受扩容操作的影响,因此在模拟真实故障中的效果更佳。实际上,我们选择了第三种方案,我们决定采用基于K8s的NetworkPolicy资源的方案进行链路层面的故障注入——允许设置如何控制Pod与网络上的各类网络“实体”通信。比如,控制给定Label下的所有Pod都不能访问某个IP。通过生成、删除这份NetworkPolicy资源就可以实现网络链路上的故障注入、恢复效果。通过在客户端和服务端之间的网络链路上配置自定义资源,我们成功模拟了网络层故障的产生和恢复,这不仅提高了演练的真实性,还减少了对下游服务资源权限的依赖。特别是对于使用云服务商或第三方资源的情况,此方法更显友好。在2024年第一季度,我们进行了深入的调研。结果显示,尽管我们已经落地了许多改进措施,但在引导业务线进行真实场景演练时,验证工作成为了一个主要的瓶颈。具体来说,我们需要进行端到端的验证,以确保演练效果的真实性。然而,这一过程仍然高度依赖于人工操作。数据显示,人工验证的比例高达39%。虽然人工验证能够提供更为真实的校验结果,但这反映出我们在自动化验证方面还有待提高。例如,缺乏有效的自动化工具或资源不足,这些限制了效率的提升。演练自动化需要一套自动化的流水线基础设施,承载演练执行、验证、恢复等关键节点。以亚马逊的流水线产品为例,它们通常会采用三层结构:Pipeline、Stage,以及Stage下的串联或并行Job。这种结构使得在持续集成/持续部署(CI/CD)的实践中,我们能够清晰地感受到流水线对自动化建设的友好和促进。在混沌工程的演练场景中,我们追求的是能够自定义的流程节点,其中每个任务都应该是灵活可替换的。我们希望能够自由地定义节点,同时确保节点内部的执行细节是可视化的。此外,我们还需要能够一键启动整个流水线,快速地进行故障模拟和验证。-
基于 K8s exec 远程执行 Chaosblade 注入和恢复脚本
-
基于 saltstack 远程执行 Chaosblade 注入和恢复脚本
-
调度 K8s job 执行 shell 脚本,实现自定义的注入和恢复逻辑
-
调度 K8s NetworkPolicy 资源,实现网络链路层的故障和恢复效果
-
自定义文本,特定场景不方便接入自动化流程的演练动作
演练自动化有其独特性,与常规的自动化测试流程相比,它更注重面向组件失效、故障考虑的的模拟及其对系统的影响。以税务计算的逻辑为例,针对不同收入等级对应的税率计算。演练的自动化测试首先会捕获用户的收入信息,然后根据该信息计算相应的税率阶梯。这个过程中,自动化测试脚本的设计就必须能够处理不同的输入,并验证每个收入阶梯的边界条件是否能够正确触发对应的税务逻辑。2.2 图1 – 税务计算的逻辑2.2 图2 – 演练用例覆盖异常场景但是,在获取用户收入信息的步骤中,如果遇到从数据库查询或者获取外部数据时逻辑就失败了,我们需要有明确的预期返回来处理这种情况。这表明,用来验证故障演练是否符合预期的的自动化测试应该要去面向故障去设计合适的用例。在我们公司,目前建设的自动化测试主要集中在UI自动化,这种方法在端到端的测试中效果尤为显著。其次是链路级别的测试,它通常从关键业务的入口开始测试。最后是针对单一应用的测试,这虽然是针对具体应用的,但在某些情况下可能会有更好的效果。在用例设计上,我们的主要想法是将系统在演练执行后的预期效果转化为自动化测试。例如,我们可能会检查在依赖失效或降级生效情况下页面是否依然可以正常访问,并且核心数据是否能够正确展示。除此之外,我们还会关注在系统降级后是否仍能查询到部分数据,以及接口层面上,关键的返回数据字段是否非空,并且不会产生错误。通过这些断言,我们可以设计出真正面向演练场景的自动化测试用例。在构建自动化演练流程时,我们的目标是创造一个能够适应多样化演练场景的框架。这意味着我们的自动化工具和流程应该能够轻松应对各种不同的演练需求,无论是针对特定强依赖场景,还是更广泛的系统稳定性测试。-
我们从最早的执行环境变更开始,这可以通过修改账户配置、开启服务降级开关,或者在预案平台上执行特定预案来实现。这个环节被抽象为一个节点,可以无缝集成到我们的自动化流水线中。
-
-
第三步是验证系统在这个新状态下的行为是否符合预期。这需要依赖我们之前讨论的自动化测试原理,并通过流水线节点进行接入,例如,接入接口自动化测试平台。
-
第四步是执行演练的恢复动作,确保系统能够返回到正常状态。最后,我们收集自动化执行的结果,将其反馈给用户。用户可以根据自己的经验进行综合判断,以研究和评估演练的结果。
传统的自动化测试可能需要手动构造请求以生成用例,但随着技术的进步,我们现在可以通过流量录制与回放功能,自动生成测试用例。这种方法允许我们在真实环境中捕获流量数据,并将其转换为可用于自动化测试的用例。在流量录制方面,酷家乐面临过环境选择的挑战。我们考虑了多种方案,包括在线上环境录制后在预发环境回放,或者在线上录制后线下回放。每种方案都有其优势和局限性。例如,在线上环境进行流量回放,需要稳定的流量达标和数据隔离能力,而线下回放需要解决线上线下数据状态不一致的问题。为了实现混沌工程五个原则之一——在生产环境中运行实验,我们选择了一种折中的方案,即在线上录制流量后在预发环境回放,这样能够利用真实的用户流量数据进行测试。在选择流量工具时,我们比较了多款流行的流量录制和回放工具。我们发现,虽然每款工具都有其独特的优点,但最适合我们需求的工具应该具备友好的用户界面、清晰的响应格式、以及支持倍数回放等关键特性。我们比较了几款流量工具,主要是Jvm-sandbox-repeater和Goreplay,最终发现,Goreplay相对更有优势。Jvm-sandbox-repeater天然具备的 Mock 能力是我们所不需要的,而且它对应用的侵入性较强,可能会造成CPU使用率升高的问题。而Goreplay直接在操作系统层面捕获网络流量,对应用层的侵入性较少,清晰的响应格式和支持倍数回放等优势明显。不过,它主要支持HTTP协议,捕获其他协议的流量可能较为困难。以某一个模拟场景为例。我们可以通过图表清晰地观察到应用程序的依赖关系,从应用视角和接口视角两个不同的维度进行分析。这种可视化的方法帮助我们识别潜在的风险点,并为演练提供了明确的目标。2.6 图1 – 依赖管理首页依赖演练流⽔线的设计直观地展示了单次演练的整个过程,从模拟网络中断的场景,到自动化测试,再到故障恢复的节点,每一步都被清晰地记录和展示。2.6 图2 – 依赖演练流水线此外,我们的接口测试结果也进行了详情展示。通过这种视图,我们可以直观地看到哪些接口通过了测试(以绿色标记),哪些没有(标记为红色)。如果测试用例的命名足够明确,我们可以直接看出依赖失效对应用的影响程度。2.6 图3 – 接口测试结果展示在自动化演练统计方面,我们在2023年第四季度进行的演练次数达到了100多次,这一数字比2021年第⼀版产品推出时的演练次数有了显著的提升。这充分体现出我们的产品不仅在应用性上得到增强,功能完善程度也有了大幅的提升。2.6 图4 – 每天演练次数综合上述的思路和要点,探索并建立了一个高效的自动化平台。目前,我们将平台分为三个主要部分——元数据管理、自动化引擎、用例系统建设。2.7.1 元数据管理
元数据管理模块的核心任务是整合和优化混沌工程中的各类演练产品。通过精确的分类和管理,我们能够确保不同类型的演练——无论是常规的、降级的、预案的,还是特殊场景下的演练——都能在平台上得到有效的管理和调度。该模块的一个重要功能是将演练场景与相关的自动化应用关联起来,确保各个元素之间的关系得到合理配置。这意味着,每一个演练场景都能够找到与之匹配的自动化流程,从而实现无缝的执行和监控。此外,元数据管理模块还集成了特定模块,如降级有效性演练,确保它们能够对接到相应的执行平台或模块。这一点尤其重要,因为它保证了降级措施能够被有效地执行和编排,特别是在故障注入和执行的阶段。随着预案平台的更新建设,我们也将其纳入了元数据管理系统,确保能够执行相关的预案。2.7.2 自动化引擎
自动化引擎包括两个关键部分:自动化流水线,即之前提到的演练过程,以及定时调度机制。通过定时调度,我们可以确保演练计划能够定期自动执行,避免人工触发导致的低效问题。2.7.3 用例系统
用例设计能够覆盖各种可能的故障场景和业务逻辑。以接口用例为例,除了常见的状态响应码和协议状态码外,我们的断言能力进一步扩展到了响应数据的深度校验。这包括但不限于验证特定字段的存在性、非空性、数据长度,以及例如集合大小等细节。在设计用例时,我们也审慎考虑了是否需要对具体的值进行断言。在某些情况下,特定值的断言可能过于独特,尤其是在降级场景中,降级数据与正常数据的有效值可能不同。因此,我们更倾向于强调数据的存在性或不存在性,这种概念对于确保数据完整性至关重要。此外,我们在UI自动化测试方面也进行了深入的探索。我们会验证页面元素的存在性,检查特定接口的调用情况,以及是否会出现问题,甚至验证接口返回数据的准确性。我们也在积极探索自动化测试之外的断言能力,例如断言某些警报、特殊日志或其他关键指标。随着混沌工程在酷家乐的深入进行,我们不仅在技术层面取得了显著的进步,也在团队协作和文化建设方面获得了宝贵的经验。以下是我的一些经验总结,供大家参考。-
演练之前要有明确的目的,不然演练结束会觉得没有效果 ;
-
强弱依赖演练、预案演练很重要,对应用能否做、怎么做降级预案有指导,真正去做到快速恢复,应急时心中不慌。条件允许是建议线上去做演练;
-
突袭演练需要好的工具支持 ;
-
演练自动化的关键还是在于演练效果验证自动化 ;
-
需要有面向演练场景的自动化用例,可能需要专门去补充 ;
-
接口类的自动化用例,可以考虑用流量录制的流量集去转化 ;(全文完)
以上问题答案,欢迎点击“阅读全文”,观看完整版解答!!!重要通知!!
如果你在某个稳定性领域有深入研究和实践,或者是技术团队的管理人员。欢迎加入TakinTalks稳定性社区专家团,以演讲、文章、视频等形式传播你的最佳实践和经验。有意可联系社区工作人员 18958048075(乔伊,微信同号)。
添加助理小姐姐,凭截图免费领取以上所有资料
并免费加入「TakinTalks读者交流群」
声明:本文由公众号「TakinTalks稳定性社区」联合社区专家共同原创撰写,如需转载,请后台回复“转载”获得授权。
更多故障治理内容
📢点击【阅读原文】直达TakinTalks稳定性社区,获取更多实战资料!
本篇文章来源于微信公众号:TakinTalks稳定性社区
本文来自投稿,不代表TakinTalks稳定性技术交流平台立场,如若转载,请联系原作者。