江帅帅,奈学教育,擅长系统架构设计,大数据,运维等技术领域;对大中后台技术有丰富经验(交易平台、基础服务、智能客服、基础架构、智能运维、数据库、安全、IT 等方向);曾担任怀致科技 CTO,并还在东软集团、中国移动、多迪集团等企业中任职过相关技术负责人。
混沌工程(Chaos Engineering)是什么,你一定听说过那只捣乱猴子的故事,今天我们来聊聊。
一、混沌工程简介
混沌工程师一门新兴的技术学科,它的初衷是通过实验性的方法,让人们建立复杂分布式系统能够在生产中抵御事件能力的信息。
—— Principles of Chaos Engineering
有没有这种感觉,当你写下第一行代码的时候,后面等着你的就是不断和系统中的各种错误做斗争?年纪大了,老是害怕在平时的工作中出各种各样五颜六色的问题,一出问题就整宿的加班通宵,熬到六亲不认,枸杞当饭吃。就好像写的代码会跳出来嘲讽你一样:百因必有果,你的报应就是我。
实际生产环境中,各种不可预期的突发事件无可避免,系统中任何地方都可能出错。那如果想要减少问题,只能让问题更多频次地暴露出来,然后各种揪头发,通过不断地重演,找到具体的问题并干掉它。琢磨可靠的解决方案,持续提升系统的容错灾备能力和弹性空间。
在最近几年,很多公司的系统架构逐渐向微服务架构演化,这对系统的扩展性要求更高了,同时也造成系统的复杂度急剧上升,导致系统的不确定性也随之增长。假如我们要进行如下的这些线上实验:模拟整个机房 IDC 宕机、选择一部分网络连连接注入特定时间的延迟、随机让一些函数抛出异常、强制 NTP 时间不同步、生成网络或者磁盘 IO 错误、榨干机器资源(比如 CPU、内存等)等,这些试验到底会有什么样的结果,有些我们可以预料,但有些可能我们无法预料,这时候,你需要了解“混沌工程”。
混沌工程(Chaos Engineering),不难理解,最初由 Netflix 提出来想从根本上去改变人们对软件系统缺陷和出现故障的不同视角和思维方式。它希望我们不要逃离现实,需要遵循自然发展的规律去看待现实中的问题。
就好比你们家孩子,到了读中学时,百分百会出现叛逆,那你首先需要的是正确去看待一个孩子的成长,知道这是必然的,然后给予更多的关怀和疏导,不断调整自己的教育方式,比如以后应该怎么说 Ta 才会听,怎么做 Ta 才是才被接受等等,而不是一味地打压或者求神拜佛让菩萨保佑 Ta 不要叛逆。
混沌工程亦可理解为一套基于在原有系统基础设施上去进行反复实验,最终找出系统中存在风险的方法学。由于开发者的能力和认知水平也有边界,不可能所有的细节都可以预估到,系统很脆弱,各种潜在不可预期的突发事件在所难免,我们需要在异常触发之前,尽可能地去筛选出会导致出现有异常问题的、容易造成故障的、系统中明显裂痕的环节。也就是混沌工程所肩负的意义,能让复杂系统中根深蒂固的混乱和不稳定性浮出水面,让我们更全面了解系统中固有的现象,然后进行及时修复、加固和防患于未然,才能打造更具弹性的软件工程系统。
混沌工程,重在实验,不同于测试。混沌工程,是发现新信息的实践过程;测试,只能让我们通过最终呈现得知这个结果是否我们预期的,要么正确,要么错误。测试偏向验证,它不能让我们去探求一些新的未知方向,或者蹦出一些我们始料未及的惊喜。而混沌工程却是我们想要的这一朵奇花,它能帮助我们获取更多、更接地气的认知维度在系统中如何采用新视角去进行实验。实验确是可以产生新的认知,实现的可能性是无限的,实现可以千变万化,根据不同的系统架构和核心业务规则,让我们在复杂系统的认知层面上还能开辟出更具价值的空间。
对于混沌工程,不针对任何特定领域或组织,它是 Netflix 提出来的方法论。混沌工程的基本原则适用于各个行业,很多行业都在不断挖掘其立足点,包括了医疗、保险、金融、农业、航天航空制造等等领域,都是非常值得期待的。
如果你准备开始使用混沌工程,最起码要保证你的系统已知的问题都已被解决了。混沌工程,是用来暴露生产系统中那些未知的、脆弱的环节。同时我们还要搭配一套监控系统来观察和判断系统当下的各项指标状态。就好比医生看病,病人必须得在现场,才能清楚知道病人的状态和具体问题,才能对症下药。
系统的复杂性,对工程师来说是一种挑战也是一种机遇。Netflix 在软件工程的决策过程中,鼓励工程师在性能、可用性、容错能力和新功能开发的速度四个维度找到平衡性,可以为架构选型提供重要的信息。他们采用了微服务架构,以小团队松耦合和高度协调的特点来提高新功能的开发速度。
复杂的系统,比如一个大型分布式系统,超多的组件,相互之间的调用乱如麻。如果它们之间发生频繁的改动和更新迭代,就会造成组件间交互异常混乱。传统的开发者,是不可能在这种系统中做到完全的掌控和理解,这也是混沌工程想从这种情境中让开发者得到解脱。
二、混沌工程原则
优化一个复杂系统的性能通常需要在混乱的边缘进行,即在系统行为即将开始变得混乱、无迹可寻之前。
—— dney Dekker, Drift Into Failure
混沌工程是一门原则性很强的学科,看似浪荡的外表,其实内心硬如刚,它也是一门实验性的学科。
我们从混沌工程试验的基本设计方法到高级原则来深入了解它。在真正实施混沌工程的大规模系统上,遵循的原则越全面,你面对系统弹性的信心就越足。
我们在实验的时候,主要想通过各种各样的实验来了解系统的表现,也会给系统制造各种麻烦,但不会给系统不同的随机输入。我们经过分析之后,期望能够最大化每个实验可以获得的信息。
Netflix 也提供了 FIT(Failure Injection Testing)故障注入测试工具,可以尝试注入一些失败场景,模拟系统由预料外的事件或不良的延迟等导致的问题,然后系统会触发相应的逻辑。
高级原则,后面会用到,具体如下:
原则一:建立稳定状态的假设
原则二:用多样的现实世界事件做验证
原则三:在生产环境中进行实验
原则四:自动化实验以持续运行
原则五:最小爆炸半径
01 / 原则一
稳定状态,用于指定一个系统倾向于维持在一定范围或模式内的属性。系统的正常运行时的状态,可以认为是系统的“稳定状态”。
我们甚至可以通过某些模型来获取对应的指标来描述系统的稳定状态,这个稳定状态一定要和客户接受程度一致。
系统指标,能帮我们诊断性能的问题和发现功能缺陷,这就需要我们借助工具去收集和系统健康有关的数据,我们可以收集 CPU 负载、内存使用情况、网络 I/O 等信息。
但大家有没有想过,业务指标,相对系统指标来说才是真正能真实地反映系统的健康状况?我们需要一个可以反映当前活跃用户满意状况的指标,因为只有客户满意,才会持续使用。
当然,我们的系统抓取业务级的指标比抓取系统级的指标肯定更难实现,但确实值得好好花精力去做的,因为只有它们才能真实地反映系统的健康状况。选择的指标与自己的还有特别重要的一点,这些指标数据越快获取越好,延迟越低越好。
描述一个稳定状态,最好建立一个有意义的假设作为前提条件。我们需要通过预先假设,才能在数据中去找对应的东西,才能得出有效的结论。比如,实验的施行不会导致系统行为偏离稳定状态。
还有,我们如何衡量稳定状态行为的变化?比如有偏离稳定状态行为发生时,如何去测量这个偏差。当我们定义清楚偏离稳定状态的偏差是否在合理的范围后,就能获得比较靠谱的验证假设的测试集了。
02 / 原则二
人生在世,活得久了,啥事儿都有可能见得到。系统也一样,都是从简单到复杂,只要它运行的时间足够长,很多不可预知的问题都会出现。
但如果我们想要完全避免不出问题,显然不可能,我们能做的是尽可能减轻这些威胁。同时我们在决定引入哪些事件时,就需要估算它们发生的概率和最终影响范围,推演造成的成本和复杂度等。
针对某些特殊的系统,还会涉及到文化因素,也是一种成本。比如,人家做传统数据中心的,就不想你这么搞,因为数据中心严格的流程控制与频繁关闭节点等操作明显是矛盾的。但后来上云了,基础设置的管理转移给云服务提供商,硬件的各类故障也由云服务平台进行管理了,这就鼓励可进一步推动混沌工程的引入和实施。
有个叫 Blockade 的工具,它是戴尔云管理团队提供的一款开源的、基于 Docker 的、用来测试分布式应用的网络故障和分区的混沌工程工具。
一般来说,调用注入异常来模拟失败部署而带来的影响应该要被隔离、限制在有限的范围内。一个故障的影响范围和隔离范围,就是这个故障的故障域。故障隔离既可以是物理隔离,也可以是逻辑隔离,隔离是容错的必要但不充分条件。想要获得可接受的结果,还需要结合某些形式的冗余或优雅降级。
当我们采用故障域的概念来实施混沌工程时,具有一定的乘数效应,能够验证服务对部署缺陷代码的弹性和引发失败时的弹性。在故障域范围内,你还可以往系统中注入各类故障来观察故障的特征。
很重要的一点,要意识到系统中的每一个资源都有可能形成一个故障域,出现在对资源有强依赖部件之间,只要跟它有关系的,都有可能被影响到,只要注入故障的根因事件就会暴露出因为有些资源共享而形成的故障域。
03 / 原则三
一上来,就要记住,实战才能更好发现问题!还记得《战狼》,吴京他们军事演习完往回走的时候,不幸遇上袭击,队友牺牲。如果他们能一直把撤退过程也当作实战的话,就不会太过掉以轻心,以致最后被袭击。
在混沌工程领域中,大家应该在离生产环境越近的地方进行实验就越好,而最好的方式是直接在生产环境中实验。传统的测试,只是测试代码逻辑是否正确,而在混沌工程中,我们更关心系统整体的行为。
就跟部队一样,要对战争充满极度自信,就应该把每次演习当做实战来做。比如,把用户的每一次动作,每一次提交的数据,都当做是敌方进攻的事件,融到生产环境中去实验,才能知道真实数据该如何去处理。
生产环境中存在的很多关于服务状态的问题,也会让我们系统备受威胁。状态在系统中无处不在,比如数据库服务、缓存服务、对象存储服务、可持久化的消息服务等等。即使在无状态的服务中,状态仍然在内存中以数据结构的形式存在于请求之间,并因此会影响后续的请求。
另外,在进行任何混沌工程实验之前,都应该有一个自动化的能够立即终止实验的方式来将潜在的影响范围最小化,主要有两个策略:
- 允许快速终止实验
- 将实验造成的爆炸半径最小化
离生产环境越近的实验是会有风险的,但冒这个风险的代价总会比将来大规模中断所带来的灾难会小。
04 / 原则四
Netflix 认为,不能也不应该让工程师牺牲开发速度,专门花时间来手动定期执行混沌工程实验。所以,搞了一个混沌工程自动化平台(Chaos Automation Platform, ChAP),以期降低创新实验的难度,然后让实验可以自动化执行。
在混沌工程的实践中,应该自动进行实验,自动分析实验结果,最好还能自动创建新的实验。如果一个实验不是自动化的,那么就可以将这个实验废弃。实验应该随着每次的变化而执行,当发现新风险时,可以阻止发布并优先处理缺陷。
另外,能够配置自动运行的实验已经很优秀了,但最好就是能自动设计实验。加州大学圣克鲁兹分校的 Peter Alvaro 教授还把一项叫做正确路径驱动的故障注入(Lineage-Driven Fault Injection, LDFI)技术与 Netflix 工程师一起研究是否能够应用到 ChAP 系统上。
05 / 原则五
混沌工程最大的风险就是会导致生产环境崩溃,所以我们要更多去理解和降低生产风险,然后设计更强的系统,阻止大规模的生产事故发生,减小对客户的影响。
混沌工程实验主要想通过多种方法来探索那些隐藏且会造成不可控的问题点,在让这些问题曝光时而不会因意外事件造成更大规模的故障,就叫“最小爆炸半径”。
任何事物都有顶峰,当你登顶之后,风险也是极大的。当你的系统给你带来很强的信心,同时也会是充满了极大的风险。混沌工程追求,实验应只承载可以衡量的风险,并采用递进的方式,进行的每一步实验都在上一步的基础之上。
最小风险的实验,只针对很少的用户进行实验,只需要向一小部分终端注入故障,作为早期实验获取早期数据指标。
如果自动化实验成功了,那么下一步,运行小规模的扩散实验。按照正常的路由规则,让流量在服务器上均匀分布,以影响一小部分用户。然后我们根据定义好的成功指标来过滤所有被影响的用户,以防实验的影响被生产环境的噪声掩盖。
再接着,就进行小规模的集中实验,通过修改路由策略将所有实验覆盖的用户流量导向特定的节点,然后在节点上可以做高度集中的故障、延迟等测试。可以模拟实验的大规模故障,但负面影响面又可以控制在很小范围。
风险最大、准确率最高的实验是无自定义路由的大规模实验。但要保证实验造成过多危害时及时能够停止,最好能够实施自动终止实验。
三、总结
以上内容主要是根据电子工业出版社的《混沌工程 Netflix 系统稳定性之道》一书进行整理,希望大家可以通过阅读此文对“混沌工程”的基本理念和使用原则有一个初步的认知。混沌工程的实践也非常重要,后头争取联合另一位业内一线大咖,再出落地实战性超强的文章,敬请关注!