目前,随着金融业的快速发展以及日益新增的需求变化,传统的单体架构已经不能满足需要,分布式系统、微服务架构正在越来越多地应用到业界中。虽然分布式系统有众多优点,但分布式的引入导致各个系统间的交互、以及底层的基础设施变得更加的复杂,因此,对系统的可用性、可靠性提出了更高的要求。为了解决分布式系统架构健壮性的验证、相关风险及应对预案的研究,我们在 2021 年年初启动了《分布式微服务平台软件风险工程 SRE 研究》课题的研究及应用实践工作,从故障驱动的角度出发,提前挖掘当前架构、链路、系统存在的隐患,验证基础设施的完备性,限制故障影响的范围,建立相关风险预案。由此,我们引入了混沌工程及故障演练,并进行了系统的研发应用及实践。
混沌工程是什么?
混沌工程是什么呢?混沌工程是在分布式系统上进行实验的学科,目的是建立对系统抵御生产环境中失控条件的能力及信心。它起源于 2010 年 Netflix 创建的 Chaos Monkey,可以随机终止在生产环境中运行的实例,工程师可以快速了解正在构建的服务是否健壮,有足够的弹性,容忍计划外的故障。至此,混沌工程开始兴起。
混沌工程通过在系统中随机注入不同类型的故障,尽可能多地识别出易出故障的环节,从而可以有针对性地对系统进行加固和防范。历经多年,混沌工程被越来越多的公司实践用以提高系统架构的可靠性。以 Netflix 为例,2010 年内部开发了混沌实验工具 Chaos Monkey 之后,仍一直致力于该方面的研究,并在 2014 年提出了故障注入测试(FIT),2015 年正式提出了混沌工程的指导思想,2017 年开源了 Chaos Monkey 的 V2 版本。此外,2016 年 Gremlin 公司正式将混沌实验工具商用化。2017 年 ChaosIQ 公司开源了 chaostoolkit 混沌实验框架。今天,许多公司包括 Google、Amazon、Microsoft、FANG、阿里巴巴、美团、奇虎 360、网易等都在研究自己的混沌工程。由此可见,混沌工程正在引起许多公司的关注,通过各种形式的混沌实验提高系统的健壮性。
那么过往实践中混沌工程都发挥了哪些作用呢?比如:工行通过对支付类交易实施混沌实验,模拟双活应用的单园区网络断连然后再恢复,发现支付链路存在一些底层故障场景下交易失败的架构设计缺陷,在投产前对支付系统架构进行了重新设计和升级,有效避免了在生产环境触发这些问题。Netflix 在过去一年中利用混沌工程提前发现了 2 次大故障和 8 次小故障,避免了整个组织大约 70 万美金的损失。京东、阿里会在双十一大促之前会进行两个月密集的混沌工程故障演练,考察故障发生的时候系统和团队对故障的检测、响应、处理还有恢复能力,提高团队对大规模故障的容错能力。
纵观上述内容,混沌工程对于提升复杂分布式系统的健壮性和可靠性发挥了重要作用,在我们的系统中引入混沌工程的应用必不可少。
混沌工程 VS 传统高可用测试的差异
由上表可知,混沌工程和传统测试方法的主要区别在于:混沌工程是发现新信息的实践过程,而故障注入则是对一个特定的条件、变量的验证方法。
当探究复杂系统如何应对异常时,对系统中的服务注入通信故障(如超时、错误等)不失为一种很好的方法。但有时我们希望探究更多其他的非故障类的场景,如流量激增、资源竞争条件、非计划中的或非正常组合的消息处理等等。我们需要探究清楚系统在这种情况下的影响。
传统高可用测试方法通过对预先设想到的可以破坏系统的点进行测试,但是并没能去探究上述这类更广阔领域里的、不可预知的、但很可能发生的事情。例如,传统测试中可以写一个断言(assertion),即我们给定一个特定的条件,产生一个特定的输出。测试一般来说只会产生二元的结果,验证一个结果是真还是假,从而判定测试是否通过。这个过程并不能让我们发掘出对于系统未知的、尚不明确的认知,它仅仅是对我们已知的系统属性可能的取值进行测验。而混沌工程实验的可能性是无限的,根据不同的分布式系统架构和不同的核心业务价值,实验可以千变万化。它和已有的测试已知属性的方法有本质上的区别。可以帮助我们获得更多的关于系统的新认知,通常能开辟出一个更广袤的对复杂系统的认知空间。
建信金科对混沌工程做的技术预研及工具选型
基于行内金融场景业务和分布式系统架构、运行环境的分析,我们的混沌工程需要具备两大特点:(1) 忽略底层基础设施,同时覆盖虚拟机和容器环境;(2)统一的流程编排模型,既能编排虚拟机又能编排容器故障。然而,业界目前还没有统一的工具能够满足上述要求。
前期对目前现有的混沌测试工具进行了调研,分析总结了各个工具故障注入的能力,如下表所示:
上表中各个工具的运行环境及故障注入能力的侧重点不同,我们选取了分别偏重于虚拟机和容器环境、故障注入类型更加全面的 ChaosMesh 和 Chaosd 开源框架。虽然这两个框架的功能点比较全面,覆盖了 k8s、网络、磁盘、CPU、内存、IO 等多个类型故障,但是还未覆盖 JVM、数据库、缓存、消息队列等异常。然而对于分布式系统来说,消息队列、缓存、数据库是非常重要的组件,这些故障注入是必不可少的。另外,分布式系统属于 Java 应用,JVM 的注入也至关重要。所以,我们对上述两个框架进行了二次开发,扩展了故障注入的能力。
由于 ChaosMesh 和 Chaosd 是两个不同的框架,不能同时模拟虚拟机和容器故障,我们需要抽象并设计统一编排模型,统一调度 ChaosMMesh 和 Chaosd,达到利用一个混沌组件同时注入容器和虚拟机两种基础设施故障的需求。
基于混沌工程研发的故障演练组件
基于 ChaosMesh 和 Chaosd 故障注入工具,我们致力于建设一套完备的混沌故障演练组件。
一、混沌工程故障演练组件架构
混沌工程故障演练组件的整体架构如上图所示,主要包含前端门户、任务调度、故障注入介质、监控告警、自定义故障、发压模块、结果分析几大模块。
1. 前端门户: 用户可快速地进行实验的编排,环境管理,预案制定,实时监控等。
2. 任务调度:完成所有实验任务的批量下发和调度。
3. 故障注入介质:接收任务调度框架下发的任务,并实施相应的故障注入事件。
4. 监控告警:采集监控的信息并整合,监控指标的存储以及定期的归档删除。
5. 自定义故障:通过二次开发进行实现开源框架未实现的故障。
6. 发压模块:模拟注入故障中的发压场景,与现有发压平台 ICDP 结合。
7. 结果分析:实验结束后,对结果的对比、分析、存储,展示。
二、支持的功能
如上图所示,故障演练组件包含了磁盘类、进程类、网络类、压力类、JVM 类、文件类、host 类、容器类等几大功能。具体到每个功能模块,又包含了常见的磁盘读写、磁盘填充、杀死进程、CPU 打满、网络延迟等典型故障。JVM 自定义类型异常注入、挡板延迟等功能还在进一步扩展开发。
三、故障演练过程
测试人员进行故障实验注入时,需要进行环境准备、故障任务编排、开始故障注入、终止注入等操作。
环境准备:开始故障演练之前,需要在门户添加被实施故障的目标服务器。
故障任务编排:故障开始之前选择了上述添加的故障环境之后,可以新建一个故障的演练任务,每个任务可以包含多个故障阶段,每个阶段可以包含多个故障步骤,每个步骤又可以包含多个故障的动作,通过对这些阶段、步骤、动作进行时序、并行、循环、定时等编排来制定一次完整的故障任务。
故障注入:故障任务编排完成之后,即可点击开始来进行故障注入,演练组件将通过故障注入介质来操作指定的目标服务器开始实验。实验进行的过程中,监控模块以及分析模块则会收集各个服务器的资源指标等信息实时展示。
终止注入:故障任务除了自动结束以外,也可以通过手动终止,故障演练组件则会下发命令到目标服务器终止实验。
当前分布式系统的应用实践
分布式系统架构如上图所示,由应用路由、配置中心、Zookeeper 集群、Kafka 消息队列、Redis 缓存、Cassandra 索引、Mysql 数据库多个组件构成。各个组件之间通过 SDK、API、同步、异步调用相结合,集群之间也涉及到数据一致性、灾备、多活等各种场景的处理,整体结构相当复杂。
由于分布式系统各个组件调用关系复杂,容易出现各种各样的线上故障。以 Redis 缓存和 Kafka 为例,Redis 可能出现大量缓存过期、缓存穿透、节点宕机、Kafka 可能出现删除部分 kafka 主题、消息队列满等故障。另外,网络异常、磁盘 IO 等系统层面的故障也呈现增长的趋势。金融行业业务场景复杂、故障场景众多、测试环境资源不足、传统测试方法单一等使我们无法及时地发现各种线上问题并修复,导致系统的健壮性不足无法应对生产环境的各种突发故障。
混沌工程则可以帮助验证分布式系统的健壮性,为此我们设计了路由层、中间件层、数据库层、缓存层、系统层等主流的应用高可用测试场景。下边以网络故障场景为例来介绍帮助更好地理解实验过程。
故障场景:由于网络发生故障,导致包损坏,且包损坏逐渐增大。一段时间后,网络被维修,故障恢复。
实验步骤:
1. 使用发压平台对应用路由发压
2. 制造一个网络包损坏的故障,将包损坏率从 20%增加到 50%,如下图:
3. 保持一段时间,恢复两次故障
实验结果如图所示:
通过本次实验反映了应用路由存在一些架构设计的缺陷并有针对性地修复,提升系统的健壮性和稳定性。截止目前对分布式系统进行的故障演练测试,已发现了 10 余个问题,正在逐步优化并制定相应的预案,有效避免在生产环境发生这些问题。
总结与展望
目前,我们已进行了混沌工程及故障演练组件的研发应用及实践,包括虚拟机/物理机上的混沌工具集、容器的混沌工具集,并将混沌工程应用到了分布式系统的具体测试中,有效地发现并针对性地修复了相关系统故障问题。从应用场景上,混沌工程也适用于各类基础平台、通用技术组件、基础软件及工具的测试,后续我们将继续拓展混沌工程的应用场景,对上述应用场景进行混沌测试,以提升系统的健壮性。
同时,随着业务规模的不断扩大以及分布式系统的不断升级,我们将在混沌工程的基础上,继续完善故障演练组件的研发来满足日渐增长的需求。故障演练组件原型如下图所示:
目前,正在原型的基础上快速扩展以下 3 个功能:
1. 环境管理:支持物理节点的简单注册、支持单个 k8s 集群和多个物理节点的实验。
2. 预案编排:支持分别制定 k8s 和物理节点的故障预案制定。
3. 实验管理:支持创建、开始、停止、展示实验的操作。
整个故障演练组件的操作调用流程结构如下图所示。
除了对分布式系统进行故障演练外,接下来会加快推进对行内其他业务编排各种故障类型的演练,逐渐稳步提升全行各个系统处理异常事故以及极端场景的能力,为行内各个系统的稳健发展提供有效的保障。
另外,我们也会加速拓展将混沌工程在分布式系统的实践应用到整个金融业场景,我们将提供一种服务化的能力,通过沉淀出的高可用场景案例集、故障编排方案,用户只需要简单使用故障演练组件即可自动化地对自身的整个集群环境做混沌故障演练,有效避免生产环境的事故。
参考文献
[1]Casey Rosenthal,Lorin Hochstein,Aaron Blohowiak,Nora Jones,Ali Basiri.混沌工程 Netflix 系统稳定性之道[M].北京:电子工业出版社,2019.
[2]吴冕冠.ChaosBlade 在工商银行混沌工程体系中的应用实践[EB/OL].2021-01-01.
本文转载自:金科优源汇(ID:jkyyh2020)
原文链接:混沌工程及故障演练组件的应用与实践
评论