本文首次发表在 IEEE Software 杂志上。IEEE Software为现如今的战略技术问题提供了可靠的、经过同行评审的相关信息。为了应对运行可靠性和企业灵活性所带来的挑战,IT经理和技术主管依靠IT Pro获得最先进的解决方案。
现代的基于软件的服务被实现为具备复杂行为和故障模式的分布式系统。Chaos工程经过实验,可以确保系统的可用性。Netflix的工程师制定了描述如何设计和运行实验的Chaos工程原理。
三十年前,Jim Gray指出,“提高可用性的一种方法是安装经过验证的硬件和软件,然后就不要管了”。1对于通过互联网提供服务的公司,“不要管了”并不是一个很好的选择。这些服务提供商必须不断地进行改变来增加服务的加入,比如他们会添加新的功能并改进性能。在Netflix,工程师将新代码放到生产环境中,每天需要修改运行时参数几百次。(有关Netflix及其系统架构的信息,请参阅侧栏。)可用性仍然非常重要:由于服务中断无法观看视频的客户可能就不会再使用我们的服务了。
但是为了实现高可用性,我们需要采用一种不同于Gray建议的方法。
多年来,Netflix都在维护Chaos Monkey,这是一款随机选择杀掉正在运行的生产服务及实例的内部服务。2Chaos Monkey旨在鼓励Netflix的工程师可以设计出能承受单个实例故障的软件服务。它只在正常工作的时间内处于活动状态,以便工程师可以在服务被杀掉后迅速做出响应。
Chaos Monkey已经被证明成功,现在所有的Netflix工程师设计出的服务都可以处理实例故障。
这一成功鼓励我们将引入故障的方法扩展到生产系统中,以提高可靠性。例如,我们执行模拟整个Amazon EC2(弹性计算云)区域故障的Chaos Kong练习。我们还执行了故障注入测试(FIT)练习,使Netflix服务之间的请求故障,并验证系统正常降级。3
随着时间的推移,我们意识到这些活动的意义比仅仅“打破正在生产中的东西”更加微妙。我们还注意到,像Amazon、4Google、4Microsoft、5和Facebook6这样的组织都在用类似的技术来测试他们的系统弹性。我们相信这些活动是我们行业新兴技术的一部分;我们称之为Chaos工程。具体来说,Chaos工程包括在分布式系统上进行实验,以建立其在生产环境下的抗压能力。这些条件包括方方面面,可能是硬件故障,可能是客户端请求意外激增,可能是运行时配置参数中的畸形值。通过经验,我们总结出了 Chaos工程的原理 ,我们也会在这里介绍。
Chaos工程的核心有两个前提。首先,工程师应该将生产中运行的一系列服务视为单个系统。其次,我们可以通过注入现实世界的输入(例如瞬态网络故障)以及观察系统边界发生的事情来更好地理解系统的行为。
在传统的软件工程方法中,功能规约描述了软件系统应该如何工作(见图1)。如果系统中包含多个程序,功能规约还定义了每个程序的工作。
图1 功能角度的软件系统。函数f定义了输入(x)如何映射到输出(y)。对于分布式系统来说,这样的功能规约是不完整的,它们不能完全展现出所有可能输入的系统行为。
在实践中,描述分布式系统的功能规约是不完整的,它们不能完全展现出所有可能输入的系统行为。这个问题会因为用户行为的规模和复杂性以及底层基础设施而加剧,因此难以完全枚举所有的输入。在实践中,系统的规模使得服务的规范对于行为的推测变得不切实际。
从系统的角度看,工程师关注于软件的动态视图。这个视角假定组织在一段时间前将软件部署到生产中,并且系统有活跃用户。工程师将系统视为单个实体,通过在边界处抓取指标来观察其行为。
工程师关心指标随时间变化的典型行为:系统的稳态行为。该行为可以通过用户交互(例如,请求的速率或类型),通过工程师最初的更改(例如,运行时配置更改或代码更改)以及其他事件,例如第三方服务依赖的系统的暂时故障发生改变。
从这个角度来看,我们提出诸如“是否正常工作?”和“用户是否抱怨?”等问题,而不是“实现的功能是否符合规范?”这样的问题。
在Chaos工程中,和其他实验学科相同,设计实验的时候需要提出假设、自变量、因变量和上下文环境。
我们相信四个原则体现了Chaos工程设计实验的方法:
在Netflix,我们使用Chaos工程来保障系统在各种不同的条件下仍能正常工作。然而,作为设计实验的基础,“正常工作”的概念太模糊了。在上下文环境中我们最关注的质量属性是可用性。每个Netflix功能(例如,参见侧栏)由不同的服务(或多个服务共同)实现,每个服务都可能会故障。然而,即使这些内部服务中的一个故障了,这个故障也不一定会影响到整个系统的可用性。
Netflix服务使用回退确保正常降级:非关键服务中的故障对于用户体验的影响很小。比如说,服务A对服务B之前的缓存服务进行请求。如果缓存服务故障了,服务A可以回退,直接向服务B做出请求。这个行为在长期内并不理想,因为请求延迟增加,且服务B上的负载也增加了,但是从短期来说用户并没有受到影响。
Netflix的其他服务会提供个性化内容,回退将会提供合理的默认值。一个例子是书签服务,如果故障,Netflix UI可以默认在开始时启动视频,而不是提供“从之前的位置恢复”的选项。
最后,我们关心的是用户是否可以找到想要看的内容并成功开始观看。我们通过观察每秒有多少用户开始流视频来实现这个概念。我们称之为SPS——每秒开始的流。8
SPS是我们评估系统整体健康的重要指标。虽然“Chaos”会给人带来不可预测的感觉,但实际上Chaos工程的基本假设是让复杂的系统表现出可以预测的行为。类似地,SPS度量在一天中缓慢且可预测地发生变化(参见图2)。Netflix工程师用了这么多时间来看SPS,他们已经培养出了一种直觉,可以判断这个值是在标准范围内的变化还是需要引起关注。如果观察到SPS的意外变化,我们就能知道系统有问题。
图2 24小时内SPS(流每秒开始)的图表。该指标在在一天中缓慢且可预测地发生变化。橙色线表示之前一周的趋势。由于数据是专有的,所以y轴并未标记。
SPS是实现系统稳态行为的度量的很好例子。Netflix另外一个这样的指标是每秒新账户注册数。这些指标和系统可用性之间存在着强健且明显的关联:如果系统不可用,用户不能打开流视频,也不能注册新账户。其他领域会使用不同的度量来表示系统的稳态行为。例如,电子商务网站可能会使用每秒完成的购买次数,而广告投放服务可能会使用每秒浏览的广告数。
当设计Chaos工程实验时,我们形成处理将会如何影响系统的稳定状态的假设。例如,Netflix在多个地理区域部署软件(北弗吉尼亚州、俄勒冈州和爱尔兰)。如果在一个区域中发生中断,我们可以规定故障时转移到另一个区域,就是将来自中断区域的客户请求重定向到没有发生中断的区域。当我们测试这样的场景时,假设从一个区域到另一个区域的故障转移对SPS影响最小。
当我们为Chaos工程制定假设时,假设也是一种特定类型的度量。例如说比较表现整个系统稳定状态的SPS指标和完整粒度的CPU负载或完成数据库查询的指标。Chaos工程实验设计侧重于前者:在系统边界处可见的稳态特征,并直接抓取用户和系统之间的交互。我们不使用粗糙粒度的指标来进行Chaos工程实验设计,因为它们不能直接测量系统的可用性。
然而,当运行Chaos工程实验来检查系统是否正常运行时,我们确实观察到了严格的度量,因为这些度量展示了用户察觉不到的服务级别的影响。例如,增加的请求延迟或CPU使用率可能是由于服务在降级模式下操作引起的,从用户角度来看系统正常工作。Netflix的服务拥有者对这些内部指标设置警告,以抓取特定服务的问题。即使SPS没有受到影响,如果指标显示系统没有正常工作,我们甚至可能提早结束实验。
“快乐路径”是软件开发中的专业术语,代表在程序中不输入会导致错误的情况或是边界情况的执行轨迹。当工程师测试代码的时候,非常可能仅仅测试快乐路径,因此代码在常用的情况下能正常运行。
不幸的是,即使没有在测试用例中覆盖到,这些错误情况和边界情况在现实世界中会发生。我们服务的客户发送错误格式的请求,我们消费的服务发送错误格式的请求,我们的服务器宕机,他们的硬盘不能启动,或者内存耗尽,网络延迟突然上升了几个数量级,客户流量突然上升。最近的一项报告指出,92%的灾难性系统故障是由于非致命性错误处理造成的。
这就引出了下一个Chaos原则:改变现实世界事件。当设计Chaos实验时,从现实世界中可能发生的所有事件中抽样选择。一个选择是查看历史数据,以查看先前系统中断时输入的数据类型,确保先前发生的问题不再发生。提供对这些历史数据的访问,是在系统中断时进行事后处理的另一个原因。
然而,任何你认为可能潜在地破坏系统的稳态行为的输入都是实验的好数据。
在Netflix中,我们使用了以下一些输入:
虽然我们的实验集中在以硬件和软件故障作为输入,我们认为使用其他种类的输入也很有价值。例如我们可以改变服务接收请求的速率,改变运行时的参数或改变通过系统传播的元数据。
在某些情况下,你可能需要模拟事件而不是注入事件。比如,在Netflix我们实际上并不会让整个Amazon区域离线,我们没有这种能力。相反,我们假设整个区域已经离线,比如说将客户请求重定向到其他Amazon区域并观察效果。最终,设计Chaos实验的工程师必须使用他们自己的判断,在保持现实性和损害系统的风险之间进行权衡。这样权衡的一个有趣的例子是Kyle Parrish和David Halsey在金融交易生产系统上进行的实验。10
在其他情况下,我们选择性地将事件应用于一部分用户。例如作为实验的一部分,我们可以将一个内部Netflix服务对某些用户不可见,但对于另外的用户正常工作。这样我们可以缩小实验的范围以降低风险。
单个服务器的计算能力在过去几十年中急剧增长。尽管有这些增长,还是不能在单个服务器上部署整个Netflix系统。没有单个服务器具有承载数百万订阅用户的计算能力、内存、存储、网络带宽或是可靠性。用于实现互联网级服务的唯一已知的解决方案是在多个服务器上部署软件,并使它们在网络上相互协调,形成分布式系统。随着微服务架构的普及11,越来越多的软件工程师将实现基于互联网的服务作为分布式系统。
唉,传统的软件测试方法不足以识别分布式系统的潜在故障。基于Netflix所观察到的故障,考虑以下两种故障模式。在这两种情况下,“客户端”和“服务端”都是指内部服务,它能充当客户端和服务端。
在第一种情况下,服务器过载并对请求的响应时间会越来越长。一个客户端在未绑定的本地队列上放置出站请求。随着时间的推移,队列会消耗越来越多的内存导致客户端故障。
在第二种情况下,客户端向cache前的服务发出请求。该服务返回不正确缓存的瞬时错误。当其他客户端发出相同的请求时,cache会做出错误响应。
这些故障模式需要集成测试,因为它们涉及到服务之间的交互。在某些情况下,可能只有在生产中才能完成集成测试。在Netflix,完全重现整个架构并运行端到端测试是不可能的。
然而,当我们可以在测试环境中重现整个系统时,我们仍然需要在生产中运行实验。这是因为在测试环境中不可能完全再现系统的方方面面,差异始终存在。例如合成客户端和真实客户端的行为区别,或是DNS配置问题。
最后的原则是利用自动化来随着时间的推移保持结果的一致性。
我们Netflix的系统不断改变。工程师修改现有服务的行为,添加服务并更改运行时的配置参数。此外,随着Netflix的视频目录发生改变,新的元数据将继续通过系统。任何一个更改都可能会导致服务中断。
由于这些变化,我们对于过去的实验结果的信心也随着时间的推移而不断降低。我们预计新的实验将首先手动运行。然而,为了让实验的结果在未来也能有所帮助,我们也必须自动化实验,以保证即使系统不断发展它们也可以反复运行。它们的运行频率取决于环境。比如说我们Netflix会在平日连续运行Chaos Monkey,并每个月运行Chaos Kong练习。
自动化运行Chaos实验的想法可能有点吓人,因为你在为系统故障埋下种子。然而,根据Netflix运作Chaos Monkey的经验表明这种自动化是可行的,让它运行可以确保新的生产服务也能承受这些故障。
在四个原则的基础上,我们是这样定义实验的:
假设有一个Netflix服务,比如说书签服务,它可以给用户提供一定价值,但是对于视频流服务并不能起到关键性作用。想像一下,我们正在设计一款实验,验证这项服务的故障不会严重地影响到流。
对于这个实验,我们可以使用SPS作为可测量输出,并检查书签服务的故障是否对SPS仅仅产生轻微的影响。我们选出一小部分Netflix的用户参与到这个实验中来,并将他们划分为对照组和实验组。对于对照组我们不会引入任何故障。对于实验组,我们选择性地将与实验组用户相关的所有服务发生故障,来模拟服务的故障。我们可以通过FIT服务选择性地使特定用户的服务故障。我们假设这两组的SPS值大致相等。运行实验一段时间之后,我们再比较SPS值。
在实验结束时,我们要么会对存在变量的情况下,系统能够保持之前的行为感到很有信心,要么会发现弱点,需要进行改进。
虽然本文中提到的概念不是新的,但是它们在改善软件系统方面的应用仍处于起步阶段。本文旨在明确一些基本概念,帮助推进实践的状态。软件系统越来越复杂,这会推动人们不断获取系统可用性的经验方法。我们希望从业者和研究界可以将Chaos工程视为一门学科,继续推进,特别是在以下领域。
我们从与其他互联网级组织的非正式讨论中了解到他们也在使用类似的方法。我们希望能有更多的组织记录下来他们是如何使用Chaos工程的,以证明这项技术不仅仅是Netflix在用。
有什么方法可以让一个组织相信Chaos工程,并让工程团队采用它?
在Netflix,我们在使用内置的工具和我们构建的基础设施。目前还不清楚Chaos实验的工具有多少能适用于组织特定的基础设施上,以及这些工具可以重用的程度。是否可以构建一组可跨企业重用的工具?
要将可能事件注入到系统的空间很大,尤其是事件的组合。研究表明,许多故障是由事件的组合所触发,而不仅仅是单个事件触发的。9你要如何决定运行什么样的实验?
如果你想和我们一起讨论Chaos工程,请通过chaos@Netflix.com与我们联系。
Ali Bastri 是Netflix的高级软件工程师和首位Chaos工程师。他主要研究领域是通过故障注入自动化检测分布式系统的缺陷,他也是Chaos原理的共同作者。Bastri在滑铁卢大学获得计算机科学学士学位。通过abasiri@Netflix.com可以联系到他。
Niosha Behnam 是Netflix的高级软件工程师,也是Traffic and Chaos团队的创始成员。他负责在Amazon Web Services区域和工具之间实现控制平面故障转移软件,从而提供对服务弹性的预测。Behnam获得加州理工州立大学,圣路易斯奥比斯波的工程管理的理学硕士和MBA联合学位以及加州大学圣克鲁斯分校的网络工程硕士学位。通过nbehnam@ Netflix.com可以联系到他。
Ruud de Rooij 是一家创业公司的软件工程师。他之前是NetflixTraffic and Chaos团队的一名软件工程师,负责edge网关软件和用于区域故障转移工具方面的流量路由。他对全球流量路由、DNS以及用不可靠的组件搭建可靠的系统非常感兴趣。De Rooij获得了代尔夫特理工大学技术信息硕士学位。通过ieee@ruud.org可以联系到他。
Lorin Hochstein 是NetflixTraffic and Chaos团队的高级软件工程师,负责保障Netflix的可用性。他对分布式系统的故障模式、操作工程和经验软件工程非常感兴趣。Hochstein获得了马里兰大学的计算机科学博士学位。通过lorin@Netflix.com可以联系到他。
Luke Kosewski 是前网站可靠性工程师和NetflixTraffic and Chaos团队的创始成员,他设计了新的方法来平衡和操作edge Traffic命中Netflix堆栈。Kosewski获得了滑铁卢大学的学士学位(专攻计算机科学)。通过lkosewski@ Netflix.com可以联系到他。
Justin Reynolds 是NetflixTraffic and Chaos团队的高级工程师。他专攻于直观工程,开发了新的方法来搭建原先太过复杂而不能使用传统方法的直观健康系统。Reynolds获得了圣何塞州立大学计算机科学学士学位。通过jreynolds@Netflix.com可以联系到他。
Casey Rosenthal 是Netflix的工程经理。他管理团队处理大数据,架构解决困难问题的解决方案,并培训他人做相同的事情。Rosenthal获得了俄亥俄大学哲学学士学位。通过crosenthal@Netflix.com可以联系到他。
查看英文原文: Chaos Engineering