1.2 混沌工程的动机

至少有三个充分的理由实施混沌工程(听起来像是一个商业广告):

❑确定风险和成本,并设定服务水准指标、目标和协议。

❑在整体上测试系统(通常是复杂的、分布式的系统)。

❑找到你忽略的“涌现性”特性。

让我们来仔细看看这些动机。

1.2.1 评估风险和成本,并设定SLI、SLO和SLA

你希望你的计算机系统运行良好,“良好”的主观定义取决于系统的性质,以及你对该系统设定的目标。大多数情况下,公司的主要目的是为所有者和股东创造利润。因此,“运行良好”的定义将是业务模型目标的衍生物。

假设你正在为一个面向全球的名为Bookface的网站工作,该网站主要用于共享猫、小孩的图片。你的业务模型可能是向用户投放针对性的广告,在这种情况下,你将需要在运行系统的总成本与销售这些广告所能获得的收入之间取得平衡。从工程的角度来看,主要风险之一是整个网站可能都无法正常运行,你将无法展示广告,也就无法获取收益。相反,如果猫的图片服务器出现问题,无法显示特定的猫的图片,可能并不是太大的问题,只会在很小的程度上影响你的利润。

对于这两种风险(用户无法使用网站,用户暂时无法访问猫的图片),你可以用美元/单位时间来估算相关成本。成本包括业务的直接损失,以及其他一些不太明显但是可能同样重要的事情,比如公众形象的损害。有一个真实的例子,福布斯评估亚马逊在2013年因网站宕机,每分钟损失66240美元参见“Amazon.com Goes Down,Loses$66240 per Minute”,Kelly Clay,福布斯,2013年8月,http://mng.bz/ryJZ。

现在,为了量化这些风险,行业普遍使用服务水准指标(SLI)。在我们的示例中,用户可以访问网站的时间的百分比可以作为一个SLI,猫的图片服务器在特定时间窗口内成功服务的请求比率也可以作为一个SLI。SLI在这里是用于针对一种事件计算出一个数值,选择正确的SLI非常重要。

甲乙双方就SLI的特定范围达成协议,这样就形成了服务水准目标(SLO),工程团队为了这个目标而努力工作。反过来,SLO可以作为服务水准协议(SLA)在法律上强制执行,其中一方同意保证某个SLO,如果没有完成,他们同意支付某种形式的罚款。

回到我们的猫和小孩图片的共享网站,作为一种计算风险的方法,SLI和SLO看起来像这样:

❑主要风险是“人们无法访问网站”,简单来说就是“宕机时间”。

❑相应的SLI可以是“服务器的成功响应与错误响应的比率”。

❑工程团队要努力达到的SLO:“平均每月服务器的成功响应与错误响应的比率>99.95%”。

再举一个例子,想象一下有一个金融交易平台,算法需要通过查询一个API在全球市场上买卖商品期货,访问速度至关重要。我们可以想象一下在交易API上设置的一组不同的约束:

❑SLI:99%的响应时间。

❑SLO:99%的响应时间<25ms,占总时间的99.999%。

从工程团队的角度来看,这像是不可能完成的任务:1%的慢查询的平均响应时间超过25毫秒,这种场景我们每年只允许出现5分钟。建立这样的系统可能是困难且昂贵的。

N个9

在涉及SLO时,我们经常以9的个数来表示特定百分比。例如,99%是2个9,99.9%是3个9,99.999%是5个9,依此类推。有时,我们也使用诸如3个9和1个5或者3.5个9的短语来表示99.95%,尽管后者在技术上不正确(99.9%是99.95%的2次方,但99.9%约是99.99%的5次方)。以下是一些最常见的值,及其每年和每天的相应宕机时间:

❑90%(1个9)——每年36.53天,或每天2.4小时。

❑99%(2个9)——每年3.65天,或每天14.40分钟。

❑99.95%(3.5个9)——每年4.38小时,或每天43.20秒。

❑99.999%(5个9)——每年5.26分钟,或每天840毫秒。

混沌工程如何帮助实现这些?为了实现SLO,你将以某种方式设计系统。你将需要考虑各种险恶的情况,而要查看系统在这些条件下能否正常运行的最佳方法就是去创建它们——这正是混沌工程的目的所在!你正在有效地从业务目标转换为对工程友好的SLO定义,你可以使用混沌工程技术对其持续进行测试。注意,在所有前面的示例中,我都是针对整个系统进行讨论的。

1.2.2 在整体上测试系统

各种测试技术在不同层级上处理软件。单元测试通常单独覆盖单个功能或较小的模块。端到端(e2e)测试和集成测试工作在更高的层级上,将整个组件组合在一起,以模仿一个真实的系统,并进行验证以确保该系统执行应有的功能。基准测试是另一种测试形式,专注于一段代码的性能,该代码可以是较低级别的代码(例如,对单个功能进行微基准测试),也可以是整个系统的性能(例如,模拟客户端调用)。

我喜欢将混沌工程视为下一个合乎逻辑的步骤,有点像e2e测试,但是在此期间,我们为引入我们希望看到的故障类型确定条件,并衡量我们是否仍能在预期的时间范围内获得正确的答案。值得注意的是,正如你将在第二部分中看到的那样,即使是单进程系统也可以使用混沌工程技术进行测试,有时这确实非常方便。

1.2.3 找到“涌现性”特性

复杂的系统通常会表现出我们最初不想要的涌现性特性。在现实世界中,出现涌现性特性的例子是人的心脏:它的单个细胞不具有传输血液的属性,但是正确的细胞结构会产生使我们存活的心脏。同样地,我们的神经元也不会思考,但是被我们称为大脑的它们相互关联的集合却会思考,正如你在阅读这些内容时所想象的那样。

在计算机系统中,属性通常是由系统所包含的运动部件之间的交互产生的。让我们考虑一个例子。假设你运行的系统中有许多服务,而所有服务都使用域名系统(DNS)服务器来查找彼此。当遇到DNS错误时,每个服务被设计为最多重试10次。同样,系统的外部用户被告知,如果他们的请求失败了,就重试。现在,想象一下,无论出于何种原因,DNS服务器宕机了,并重新启动。当重新启动时,它会收到被重试层放大的大量流量,这些流量远远超过了系统所能处理的大小。因此,它可能再次失败,并陷入重新启动无限循环,而系统作为一个整体也是宕机的。系统的任何组件都不具有创建无限宕机时间的特性,但是如果将这些组件放在一起,并且事件的时机正确,系统作为一个整体可能会进入那种状态。

尽管肯定没有我之前提到的意识示例那样令人兴奋,但是从系统各部分之间的交互作用中涌现出的这种特性是一个真正要解决的问题。这种意外行为会对任何系统(尤其是大型系统)造成严重后果。好消息是,混沌工程技术擅长发现此类问题。通过在实际系统上运行实验,通常可以发现简单、可预测的故障如何级联成大问题。并且你一旦知道了它们,就可以修复它们。

混沌工程与随机性

在进行混沌工程设计时,你通常可以使用随机性元素,并从模糊测试输入伪随机有效载荷的实践中借鉴,以试图找出你有意编写的测试可能会遗漏的错误。随机性肯定会有所帮助,但我要再次强调,控制实验对于理解结果是必不可少的。混沌工程不仅仅是随机破坏事物。

希望我引起了你的好奇心,并且现在引起了你的注意。让我们看看如何进行混沌工程!