关键字
- 功能规约不能描述分布式系统,因为我们不能描述所有可能的输入,因此需要在 Chaos 工程中验证系统的可用性。
- 服务的集合应该被视为一个单一的系统,所以当注入现实世界的故障时,我们能在系统边界发现问题,这非常可能直接影响使用。
- 找出并监控描述系统稳定状态(可用性)行为的指标。在 Chaos 工程实验期间你将制定关于稳定状态(指标)如何变化的假设。
- 为了有效地覆盖故障场景,注入现实世界的故障范围需要很广(比如终止实例,模拟整个 Amazon 区域不可用)。然而,工程师需要衡量注入事件的现实性和对系统造成的风险。
- Netflix 运行的任何实验都要使用对照组(这些用户的服务运行没有改变)和实验组(无论是否可见,对这组用户注入故障),并在实验期间寻找他们之间稳态的差异。
本文首次发表在 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 工程中,和其他实验学科相同,设计实验的时候需要提出假设、自变量、因变量和上下文环境。
我们相信四个原则体现了 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 中,我们使用了以下一些输入:
- 终止虚拟机实例。
- 服务之间的请求中注入延迟。
- 服务之间请求故障。
- 内部服务故障。
- 使整个 Amazon 区域不可用。
虽然我们的实验集中在以硬件和软件故障作为输入,我们认为使用其他种类的输入也很有价值。例如我们可以改变服务接收请求的速率,改变运行时的参数或改变通过系统传播的元数据。
在某些情况下,你可能需要模拟事件而不是注入事件。比如,在 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 的经验表明这种自动化是可行的,让它运行可以确保新的生产服务也能承受这些故障。
运行 Chaos 实验
在四个原则的基础上,我们是这样定义实验的:
- 定义稳定状态作为衡量正常行为的系统可测量输出。
- 假设这种稳定状态将在对照组和实验组中保持。
- 引入反映现实世界事件的变量,比如服务器崩溃,硬盘驱动器故障和网络连接中断。
- 尝试通过找到对照组和实验组之间稳定状态的差异来反驳假设。
假设有一个 Netflix 服务,比如说书签服务,它可以给用户提供一定价值,但是对于视频流服务并不能起到关键性作用。想像一下,我们正在设计一款实验,验证这项服务的故障不会严重地影响到流。
对于这个实验,我们可以使用 SPS 作为可测量输出,并检查书签服务的故障是否对 SPS 仅仅产生轻微的影响。我们选出一小部分 Netflix 的用户参与到这个实验中来,并将他们划分为对照组和实验组。对于对照组我们不会引入任何故障。对于实验组,我们选择性地将与实验组用户相关的所有服务发生故障,来模拟服务的故障。我们可以通过 FIT 服务选择性地使特定用户的服务故障。我们假设这两组的 SPS 值大致相等。运行实验一段时间之后,我们再比较 SPS 值。
在实验结束时,我们要么会对存在变量的情况下,系统能够保持之前的行为感到很有信心,要么会发现弱点,需要进行改进。
Chaos 工程的未来
虽然本文中提到的概念不是新的,但是它们在改善软件系统方面的应用仍处于起步阶段。本文旨在明确一些基本概念,帮助推进实践的状态。软件系统越来越复杂,这会推动人们不断获取系统可用性的经验方法。我们希望从业者和研究界可以将 Chaos 工程视为一门学科,继续推进,特别是在以下领域。
其他领域的案例研究
我们从与其他互联网级组织的非正式讨论中了解到他们也在使用类似的方法。我们希望能有更多的组织记录下来他们是如何使用 Chaos 工程的,以证明这项技术不仅仅是 Netflix 在用。
采用
有什么方法可以让一个组织相信 Chaos 工程,并让工程团队采用它?
工具
在 Netflix,我们在使用内置的工具和我们构建的基础设施。目前还不清楚 Chaos 实验的工具有多少能适用于组织特定的基础设施上,以及这些工具可以重用的程度。是否可以构建一组可跨企业重用的工具?
事件注入模型
要将可能事件注入到系统的空间很大,尤其是事件的组合。研究表明,许多故障是由事件的组合所触发,而不仅仅是单个事件触发的。9 你要如何决定运行什么样的实验?
如果你想和我们一起讨论 Chaos 工程,请通过 chaos@Netflix.com 与我们联系。
参考书目
- J. Gray, 计算机为何止步不前?我们能做什么? tech. report 85.7, Tandem Computers, 1985
- C. Bennett and A. Tseitlin, “ Chaos Monkey 野外放生,” Netflix Tech Blog, 30 July 2012.
- K. Andrus, N. Gopalani, and B. Schmaus, “ FIT: 故障注入测试,” Netflix Tech Blog, 23 Oct. 2014.
- J. Robbins et al., “弹性工程:学会拥抱失败,” ACM Queue, vol. 10, no. 9, 2012.
- H. Nakama, “探秘 Azure 搜索: Chaos 工程,” blog, Microsoft, 1 July 2015.
- Y. Sverdlik, “ Facebook 关闭整个数据中心来测试弹性,” Data Center Knowledge, 15 Sept. 2014.
- W.R. Shadish, T.D. Cook, and D.T. Campbell, 广义因果推理的实验和实验设计, 2nd ed., Wadsworth, 2001.
- P. Fisher-Ogden, C. Sanden, and C. Rioux, “ SPS: Netflix 流媒体之命脉,” Netflix Tech Blog, 2 Feb. 2015.
- D. Yuan et al., “简单的测试可以防止最关键的故障:分布式数据密集系统中的生产故障分析,” Proc. 11th USENIX Symp. Operating Systems Design and Implementation (OSDI 14), 2014.
- K. Parrish and D. Halsey, “太大的测试:打破生产经济平台,而不导致财务破坏,” presentation at Velocity 2015 Conf., 2015.
- S. Newman, 搭建微服务, O’Reilly Media, 2015.
有关作者
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
评论