使用 STAMP 提高 Google 生产系统的弹性


Google SRE 采用了系统理论和控制理论:由麻省理工学院 Nancy Leveson 教授开发的 STAMP(系统理论事故模型和过程)框架,该框架将重点从防止单个组件故障转移到理解和管理复杂的系统交互。STAMP 结合了基于系统理论的因果分析 (CAST) 等工具用于事后调查,以及系统理论过程分析 (STPA) 用于危害分析。

在本文中,我们将探讨传统方法的局限性并向您介绍 STAMP。通过实际案例研究和经验教训,我们将向您展示为什么我们相信 STAMP 不仅代表 Google 的 SRE 的未来,而且代表整个科技行业的未来。

背景上下文
SRE 一直致力于不仅对故障做出反应,而且预防故障

但事实证明,预测故障在 Google 非常困难,因为 Google 的系统由历史上最大的代码库之一定义。而 AI 只会增加这一挑战。

SRE 如何理解和管理我们系统日益复杂的情况,在故障发生之前预测潜在故障,并从头开始设计更安全、更可靠的系统?
答案在于范式转变

系统理论、控制理论及其通过系统思维解决问题的应用为 SRE 提供了一种理解和管理复杂性的方法,一直到 Google 的行星级系统。
SRE 的未来将使用系统理论方法在 AI 时代提供全面、高效和有效的结果。

介绍这个新模型的最简单方法是将其与我们传统上思考系统的方式进行对比。一般来说,任何危害分析方法都由三部分组成:

  • 系统建模的方法
  • 解释问题如何发生的方法(因果理论)
  • 搜索算法
 SRE 已经开发出一种有效的方法来分析系统中的风险。与每个软件工程组织一样,我们依靠准确的软件架构模型来了解事物的工作原理。这些模型通常是数据流模型,显示网络请求或数据如何在系统的不同部分之间移动。

这种建模技术产生了一种常见的默认因果推理,用于解释问题可能如何发生。我们深入思考线性数据流模型中的依赖关系——可靠的操作源于对依赖关系的精心管理。我们使用 SLO 来了解系统中不同组件的可靠性保证,并确保这些保证满足或超出调用者的要求。

最后,我们通常使用归纳法来寻找危险。归纳法,即从离散事件到一般模式的自下而上的推理,是我们在事后分析中编写行动项目的方法。我们要求事后分析:

  • 不仅考虑修复一个事件,
  • 还要考虑如何防止一整类事件的发生。
我们利用事后分析来识别整个 Google 的模式和趋势。

我们要求 SRE 团队对他们的运营中断做同样的事情。SRE 的目标是将离散警报转化为工程解决方案,从而彻底消除问题的根源。

这些做法对我们保持可靠性的能力至关重要,同时扩大了我们的运营范围,每天为数十亿用户提供服务。它们让我们从失败中吸取教训,逐步改进我们的系统,并在整个组织内建立一种可靠性文化。

然而,我们看到我们的系统每年都变得越来越复杂,数据流模型无法适应我们巨大的复杂性。如果没有一致的方式来使用抽象,RPC 图和软件架构模型就会变得太复杂而无法分析,而且几乎总是不完整或过时的。

这些类型的模型也没有提供有关系统动态的信息。 

  • 哪些 RPC 可以启动流程? 
  • 错误如何传播? 
  • 哪些组件可能导致严重停机?哪些组件只能导致轻微问题? 
  • 如果一个组件交互在某些情况下是安全的,但在其他情况下却不安全,该怎么办?
  • 该系统试图实现的总体目标是什么? 
  • 相对于总体目标,系统中的每个组件承担什么责任? 
看到包含 100 多个节点的数据流图,你会感到不知所措——你从哪里开始寻找缺陷?更隐蔽的是系统构建需求定义阶段出现的缺陷。设计可能完美地实现了其要求。但如果系统安全所需的要求不正确,甚至更糟的是,完全缺失,该怎么办? 

从失败中吸取教训并不一定能帮助你预测和防止从未发生的事情。当有大量数据可供参考时,归纳推理非常有用,但我们会非常努力地防止往往是这些数据来源的失败。

总的来说,过去十五年来,我们对可靠性的方法一直致力于确保我们的系统按照我们设计的方式正确、一致地运行。

利用系统思维,SRE 的未来将解决第二个甚至更基本的问题:“我们设计它的方式”是否正确?
回答这个问题需要一种新的方法。

STAMP 概述
系统设计首次挑战其创造者的理解能力是在二十世纪初。复杂的制导系统、电子计算机、火箭和雷达都推动工程师超越了传统工具(组件分析、基于观察到的输出的手动调整和反复试验)所能处理的范围。作为回应,数学、工程和系统思维的交叉领域出现了一个新领域:控制理论

今天,当我们在一个日益复杂的自主系统、自适应网络以及人工智能和机器学习驱动的系统世界中航行时,战后形成时期发展起来的控制理论原理继续为管理和优化各个领域的系统提供理论支撑。

莱维森在 21 世纪初对 STAMP 的开创性工作代表了系统安全的范式转变。在控制论先驱诺伯特·维纳和鲁道夫·卡尔曼等控制理论家奠定的基础的基础上,莱维森认识到安全是一种只能在系统层面进行分析的新兴涌现属性,而不是单个系统组件的属性。

STAMP 将控制理论原理应用于安全工程,将事故视为系统组件(包括人类操作员和软件)之间复杂的相互作用,而不是一系列事件

如今,莱维森的 STAMP 方法为理解和减轻复杂社会技术系统中的风险提供了一个强大的框架,证明了控制理论原理在我们快速发展的技术环境中具有持久的相关性和适应性。

控制理论作为基础 - 四个条件
在《控制论导论》中,WR Ashby 列出了控制的基本要求,后来 Leveson 将其融入了她的 STAMP 方法论中。Leveson 认识到这些控制论原理与系统安全的相关性,并将它们用于分析系统安全。 
“为了控制一个过程,需要四个条件:

  • 目标条件:控制器必须有一个或几个目标(例如,维持设定点)。
  • 动作条件:控制器必须能够影响系统的状态。在工程中,执行器实现控制动作。
  • 模型条件:控制器必须是(或包含)系统的模型。
  • 可观测性条件:控制器必须能够确定系统的状态。在工程术语中,系统状态的观测由传感器提供。
这四个条件提供了一种结构化的方式来思考复杂系统中的控制。在将 STAMP 应用于我们的 SRE 实践时,我们可以将这些条件用作检查表,以确保我们具备有效控制的必要要素。

将事故视为控制问题重点
解释 Google 停机原因的一种普遍方法是将其视为线性故障序列。正如我们将要展示的,这种因果关系模型在分析系统安全性时存在局限性。

在我们的事后分析中,诸如“一个错误加上速率限制不足,导致数千台服务器离线”之类的句子比比皆是。

STAMP 将我们对事故的看法从线性的故障事件链转变为控制问题。

我们希望我们的模型能够解释:

  • 由组件故障(如服务器崩溃和自动化缺陷)导致的事故,
  • 以及外部干扰(数据中心或海底互联网电缆中的环境因素)、
  • 系统组件之间的相互作用(包括人与人、人与软件和软件与软件之间的相互作用),
  • 以及单个系统组件的不正确或不充分的行为——有缺陷的算法或决策。
我们不再问“哪个软件服务失败了?”,而是问“系统各部分之间的哪些交互控制不充分?”

在复杂系统中,大多数事故都是由组件之间的交互引起的,这些组件都按设计运行,但共同运行就产生了不安全的状态。(类似两个人一男一女都很正常,结婚后就都变得不正常)

危险状态给你时间
事故模型的另一个非常重要的含义是它可以帮助您分析事故的时间维度。

在线性链中,事件的顺序随时间推移而变化,但它仅描述系统可能处于的两种状态:

  • 正常(链中最后一个事件发生之前且系统尚未发生事故)
  • 故障(链中最后一个事件发生且事故开始之后)。 
从正常到故障的转变通常非常突然: 几乎没有时间做出反应来阻止它。

这就是为什么 SRE 使用快速运行和慢速运行SLO 的组合来检测可能正在发展但尚未造成实际损害的问题的原因之一。
但是,这些 SLO 通常是单个系统组件的属性。  

STAMP 在系统层面将这一概念形式化为危险状态:
“危险是一种系统状态或一组条件,与一组特定的最坏环境条件相结合,将导致 [系统中一个或多个利益相关者的] 损失。” (STPA 手册,17)

  • 危险状态不是离散事件:它们不描述单个系统组件级别的任何内容。
  • 危险状态是整个系统的一个属性,在事故发生之前,系统可以长时间处于危险状态。
这为工程师在尝试防止停机时提供了更大的目标:
  • 我们不是试图消除系统中任何地方可能发生的任何单一故障,而是努力防止系统进入危险状态。
  • 如果我们确实进入了危险状态,如果我们可以检测到它并采取措施从危险状态过渡回正常运行,我们就可以防止任何事故发生。
在某些情况下,系统会长时间处于危险状态 - 引入了错误但从未触发,发出了警报但无人收到,服务器配置不足但突然收到来自热门新产品功能的流量等。

通过真实的例子使其具体化
这种现象的一个例子发生在 2021 年的谷歌。我们为基础设施上运行的某些内部软件设置并执行资源配额。

为了最大限度地提高效率,我们还监控每个软件服务使用了多少配额。
如果某项服务使用的资源持续低于其配额,我们会自动减少配额。
用 STPA 术语来说,这个配额调整器有一个控制操作来减少服务的配额。
从安全角度来看,我们会问这个动作什么时候不安全:举个例子,如果调整器曾经将服务的配额降低到该服务的实际需求以下,那将是不安全的——该服务将资源匮乏。这就是 STPA 所称的不安全控制行动(UCA)。

STPA 分析系统中的每个交互,以全面确定必须如何控制交互才能使系统安全。不安全的控制操作会导致系统进入一个或多个危险状态。只有四种可能类型的 UCA:

  1. 未提供所需的控制操作。
  2. 提供的控制措施不正确或不充分。
  3. 在错误的时间或按错误的顺序提供了控制措施。
  4. 控制动作停止过早或持续时间过长。

这种特定的不安全控制行动(将分配的配额减少到低于服务要求的配额)是第二种 UCA 的示例。

仅仅识别这种不安全的控制行为本身只是部分有用。如果“配额权限调整器将分配的配额减少到服务要求的水平以下”是不安全的,那么阻止这种行为就是系统必须做的,即“配额权限调整器不得将分配的配额减少到服务当前要求的水平以下”。这是一项安全要求。安全要求对于制定未来设计、制定测试计划和帮助人们理解系统非常有用。

说实话:即使是成熟的软件系统也可能以无文档、不明确和令人惊讶的方式运行。

尽管如此,我们真正想要的是预测导致危险状态的所有具体情景。同样,STPA 有一个简单而全面的方法来构建分析,以找出可能导致配额调整者违反此安全要求的所有情景。

因此,在合适规模案例中,我们可以研究四种典型场景。

  1. 权限分配器出现不正确行为的场景。
  2. 合适人选得到错误反馈(或根本没有反馈)的情况。
  3. 配额系统从未收到来自权利规模制定者的操作(即使权利规模制定者尝试发送操作)的情况。
  4. 配额制度出现不正确行为的场景。
在分析 rightsizer 时,我们很快发现了一个特定场景。它从配额服务获取当前资源使用情况的反馈。在实施过程中,当前资源使用情况的计算非常复杂,涉及不同的数据收集器和一些棘手的聚合逻辑。如果这个复杂的计算出现问题,导致值太低怎么办?简而言之,rightsizer 会完全按照设计做出反应,并可靠地将服务的配额缩减到不正确的较低使用水平。 

这正是我们想要防止的灾难。 

到目前为止,人们已经投入了大量精力来确保配额调整算法正确,并可靠地产生正确的输出,即调整服务配额的操作。然而,反馈路径(包括服务当前的资源使用情况)却不太为人所知。 

这凸显了 STPA 的一大优势——通过查看系统级别并根据控制反馈回路对系统进行建模,我们发现控制路径和反馈路径中都存在问题。随着我们在越来越多的系统上运行 STPA,我们发现反馈路径通常不如控制路径那么容易理解,但从系统安全角度来看,反馈路径同样重要。

当然,重大事故从来都不是简单的事件。

下一个问题是,尽管添加了延迟作为安全功能,但有关待定更改的反馈从未发送给任何人。整个系统处于危险状态已有数周,但由于我们没有预料到这种情况,我们错过了防止随后发生损失的机会。几周后,配额减少导致严重中断。使用 STPA,我们已经预见到 Google 的许多不同系统中都存在类似的问题。

正如莱维森在《构建更安全的世界》中所写:“在 [STAMP] 中,要了解事故发生的原因,就需要确定控制措施无效的原因。要防止未来发生事故,就需要从关注预防故障转向更广泛的目标,即设计和实施将强制实施必要约束的控制措施。”

观点的转变 :

这是我们系统安全方法的一个关键原则。

总结
我们利用 STPA 分析了 Google 的一些最复杂的系统,并且花费了相对较少的努力(想想:工程师每次分析需要数周的工作量),我们发现了数百种影响范围广泛的场景。由于我们在这些场景导致中断之前就发现了它们,因此我们能够通过快速“临时”修复和更精心规划的软件工程相结合来缓解它们,利用整个 Google 的常规规划流程来提高系统安全性,同时最大限度地减少与工作相关的成本和中断。

网友:
1、这让我想起了 Sidney Dekker 的作品,特别是《理解人类失败的实地指南》和《陷入失败》。

  • 前者侧重于对整个系统进行评估,识别事故参与者的心理状态,并评估是什么让他们相信他们做出了正确的决定,同时认识到没有人希望飞机坠毁。
  • 后一本书更多地讨论了对复杂的松耦合系统的多个看似独立的改变如何导致安全覆盖范围中不明显的漏洞,以及如何避免这些情况。
我认为 CAST 方法看起来很有吸引力。它似乎确实需要对失败和险些失败进行大量分析才能得到最佳利用,而实施过程中最困难的部分无疑是那些经常持有“没有失败,我们为什么要花时间和精力调查成功”心态的人。

Dekker 是 CAST 和 STAMP 的宝贵补充,因为 Dekker 强调心理学、目标、信仰等方面的人为因素,而 CAST 强调流程、实践、指标等方面的工程因素。
CAST 描述了如何通过让利益相关者写一份简短明确的安全理念,务实地将人员方面和工程方面结合起来:
https://github.com/joelparkerhenderson/safety-philosophy

2、本文描述了基于系统理论的因果分析(CAST),它类似于多因素根本原因分析。
我是软件团队 CAST 的忠实粉丝,也是领导 CAST 的麻省理工学院教授 Nancy Leveson 的忠实粉丝。
我为技术团队提供的 CAST 总结说明:
https://github.com/joelparkerhenderson/causal-analysis-based...

MIT CAST 手册:
http://sunnyday.mit.edu/CAST-Handbook.pdf

3、自动化测试有两个问题:

  • 1)测试运行时间太长
  • 2)难以找到故障的根本原因。
大多数开发人员通过大量使用模拟/伪造来使单元测试更加精细,从而解决了这个问题。从狭义上讲,这“解决”了两个问题:测试运行速度更快,并且故障的根本原因显而易见。
但你实际上并没有解决问题。因为编写测试的整个目的首先就是回答这个问题:“我的系统能正常工作吗?”精细和模拟的单元测试没有多大帮助。

然而,回到最初的问题,我们实际上可以将问题重新定义为:

  • 1)工作调度问题和
  • 2)信号处理问题。
这些都是很好理解的问题,并且有很好的解决方案。只是这是一种比较新颖的测试思维方式​​,因此它还没有真正被集成到开源工具链中。

您可以想象集成测试会自动与微服务发布相关联。一些 CI 自动化不断在一系列提交上运行昂贵的测试,并在失败时自动进行二分法。等等。

换句话说,自动化测试还远远不够。我们还需要更高层次的抽象。计算机更擅长决定运行什么测试以及何时运行,也更擅长解释结果。

4、以下是思考 CAST 的一种快速、简单、实用的方法:

  1. 因果关系:新手可能认为事故是由一个“根本原因”或几个“可能原因”造成的,但事实证明,事故实际上是由许多相互作用的原因造成的。
  2. 分析:新手可能会责怪他人,但更明智的做法是,不带任何责备地检查损失发生的原因和过程,即“问为什么和如何,而不是问谁”。
  3.  系统:新手可能只会修复一个损坏的东西,但事实证明,最好发现多个原因,然后规划多种方法来改进整个系统。

5、Google SRE 最重要的一点(至少在早期)是,如果你的团队要推出一款新产品,你就必须有一个 SRE 来帮助和维护该服务。
Google 故意限制了 SRE 的数量,所以你必须证明你的产品有效并将其卖给 SRE 才有机会推出。
约束有助于使好的想法变得更好......但是好的想法数量就少了。

Orkut 项目基本上被禁止作为 Google 官方产品发布或营销,因为它被 SRE 视为“尚未准备好投入生产”。尽管如此,它在巴西和其他几个国家还是获得了巨大的市场份额,最终输给了 FB。当他们的“准备好投入生产”的产品 (G+) 发布时,已经晚得可笑了。

6、关键的要点是不要相信你的输入。

代码正确性确实通常归结为“给定输入 X,程序将正确地给出输出 Y”,但实际问题是有时输入 X 本身可能是错误的。

我认为这在项目管理中很明显,人们告诉你一件事,你据此计划,然后他们做另一件事,如果你没有预测到这一点,你就完了。

如果这种行为在人类项目中如此普遍,我认为它没有理由不会出现在软件项目中。

问题是,试图利用输入做一些聪明的事情的软件很难推理,这反过来又增加了你失败的可能性,而这正是你一开始想要避免的事情。例如,假设你的脚本中有一个极端情况,你想执行“rm -rf /”,但安全机制阻止你这样做,这实际上会使你的脚本失败。

总之,以我的拙见,安全性最重要的部分是选择最容易推理的工具

  • 如果你有一个 bash 脚本,你肯定会有一些与某些极端情况相关的错误 - 管理 POSIX 的人意识到 bash 从根本上就存在问题,所以最好禁止某些文件名而不是修复 bash。
  • 使用 Python 库可以获得 10 倍的安全性,但舒适度只有一半。
  • 如果你有一个 C++ 程序,无论你如何努力,它都会泄漏内存。等等。

同样,在编写程序时,您应该对其 API 做出简单而有力的承诺。永远不要说“程序接受最合理的日期字符串并尝试解析它”,而要说“要么是这种特定格式,要么是错误”。

验证输入明智地处理它们是一个好主意,但应谨慎使用,因为它可能会产生惊人的适得其反的效果。

7、SRE 现在有了区别:

  • 有的 SRE(主要)编写软件,
  • 有的 SRE(主要)盯着图表并处理随机系统故障,
  • 现在有的 SRE 使用框架来开发多个系统的复杂风险模型(这更多的是质量控制而不是工程)。
最初是由一个人想让开发人员和系统管理员一起讨论部署的方式,这样他们就不会出现死猫综合症。它最终发展成为整个业务管理理论的分支,顾问和一大群无知的人