百万个冷知识百万个冷知识

百万个冷知识
一起学习百万个冷知识

Facebook 如何做大规模服务的自主测试(Facebook主页成效分析)

容许开发人员加速升级换代特性的蓝本内部结构设计、试验和插值,对 Facebook 的成功非常重要。要想有效地同时实现这一点儿,关键是要有两个稳定的基础建设,因此不会带来无谓的摩擦。如果有关的基础建设还必须扩大,以支持全球 30 多亿元人口,利用不断增长的INS13ZD,和应对两个极其庞大且不断增长的标识符库,那么这一点儿显然更加具有诱惑力。

解决那个问题的两种形式是更好的抽象化和智能化试验。抽象化包含了面向服务项目的基础建设,它容许业务方法论内部结构变成独立撰写、部署和扩充模块。虽然这对加速插值非常重要,但也增加了试验的复杂程度。在检查和服务项目中的方法论时,模块试验是有用的,但难以试验服务项目间的倚赖亲密关系。软件系统试验可以起到挽救作用,但,相对技术标准的模块试验架构来说,没有整套的软件系统试验架构可供他们用于后端服务项目。因此他们内部结构设计并构建了那个。

Facebook 的基础建设眺望快照,强调了后端试验快捷键。

今天,他们将详细介绍在那个软件系统试验基础建设之上建立的两个捷伊独立自主试验扩充,因此也是对这一基础建设这类的主脑观察。那个扩充先进经验了模糊试验的理念,即一种智能化技术,它采用乱数输出来发现 bug,并DOM栈的异质性来提供更多点对点的开发体验,引导加速插值。迄今,Facebook 的大多数独立自主试验集中在他们的后端,或者透过 Infer、Sapienz 和 Zoncolan 等工具进行的安全试验。在此,他们将探讨他们怎样独立自主试验后端服务项目。

软件系统试验基础设施

软件系统试验基础建设须要引导技师撰写有效的试验,在须要时自动运转试验,并以简单的形式显示结论。这种形式透过提供更多标识符架构、试验运维和继续执行能力,和持续软件系统系统的适当钳子来同时实现这一点儿。标识符架构PCB了样板工程文件,并提供更多了常用的抽象化和模式,以消除撰写试验时采用柱状内部结构等常用圈套。责任编辑探讨了撰写试验的三个方面,侧重于与软件系统试验有关的部分:表述试验环境、指定输出和检查和输出。

软件系统试验的模块。试验基础建设为技师撰写试验提供更多了基础,并为运转试验提供更多了继续执行平台。

表述试验环境

为提供更多确定的结论和防止过敏反应,试验通常无此生产Escrow。这对模块试验尤其适用,模块试验集中于两个小的标识符模块,采用演示或波镇来替代外部倚赖。虽然这样做可以防止过敏反应,但它有不利的一面,那就是试验系统没有足够逼近。演示程序这类仅同时实现了一些真正倚赖亲密关系中的行为。因此,有些 bug 可能难以检测到。维护演示也须要相当大的工程努力。

软件系统试验较少倚赖演示。试验后端服务项目通常涉及两个或多个未修改的服务项目。无需修改服务项目进行试验,这有一些好处。第一,它防止了服务项目所有者的负担,但更重要的是,它使试验与在生产中运转的标识符相同,从而使它们更具代表性。

这提出了两个必须解决的重要挑战。首先是创建试验环境,适合运转未修改的服务项目。其次,必须确定怎样设置试验环境的边界和怎样处理这些边界之间的连接。

这些挑战要求采取务实的做法。他们的解决方案重用生产基础建设,尤其是用于构建试验环境的容器化和路由器系统。但,他们在基础建设中为每两个试验创建单独的短暂实体。这样,试验环境就可以不接受生产请求,而不自动限制连接到生产系统。这使得一些试验可以与生产环境共享只读资产或 API。与此同时,他们采用附加的隔离层来限制其他试验到生产系统的连接。

透过基于希望检查和的服务项目交互,他们授权服务项目所有者表述试验环境的边界。在相同环境中,与调用者运转的服务项目优先提供更多网络请求。如果环境中不存在适当的服务项目,请求可以转到演示、转到生产系统的内存副本,或者被阻止,或者转发到生产环境(例如,只读请求)。

对此设置,演示是透过动态创建和启动两个服务项目来工作的,那个服务项目与原始服务项目具有相同的接口,但同时实现形式简单。演示服务项目运转在试验工具所在的地址空间中。这样可以方便地进行交互。可以在运转时更改演示同时实现,这与更改模块试验演示的形式相似。他们把每个演示方法处理程序包装成两个标准的 Python MagicMock 或 StrictMock。透过这样操作,可以轻松地检查和它的调用次数和它接收的参数。

对常用的倚赖亲密关系,例如存储,内存复制非常有用。出这些快捷键外,试验基础建设还组织了试验环境中的连接。稍后,他们将在独立自主试验中详细探讨那个问题。

试验输出

通常来说,试验输出是以试验工具的形式提供更多的,它是两个在试验环境中与试验服务项目一起继续执行的程序。两个试验工具可以直接继续执行服务项目,也可以透过远程调用(RPC),或者在试验环境中间接继续执行更改。举例来说,它可以应用捷伊全局配置设置或者关闭试验服务项目的副本,虽然试验架构为这些操作提供更多了原语,但构建试验由服务项目所有者负责。

在软件系统试验中,模板是另一种输出源。可将其配置为发送特定的响应,从根本上作为被测服务项目的输出。倚赖失败代表输出的一种特殊情况,可以透过抛出演示中的异常来演示。

试验 Oracle

大多数试验 Oracle 都是针对服务项目行为的自表述断言。虽然这些断言原则上和模块试验断言类似,但它们只能检查和被测服务项目的外部可见行为,而非内部状态。它包括 RPC 响应、传递到演示调用的参数、写入到短暂的试验数据库的数据和其他示例。

可扩充性

软件系统试验基础建设的内部结构设计目标之一就是让团队能够在其之上构建扩充。对那个扩充,他们主要有两种用途。首先要解决团队服务项目中心出现的常用模式,例如试验环境设置或者经常采用的自表述。它们还可以为特定类型的试验表述基础,例如灾难准备试验。在须要时,这些试验验证了他们能够从头启动最基本的基础建设服务项目。比如 ZooKeeper。

独立自主软件系统试验

上述架构为服务项目所有者撰写软件系统试验提供更多了架构。但,在很多情况下,试验基础建设可以透过提供更多合理的默认值甚至自动生成所有试验模块来做得更好。

要表述试验环境,那个基础建设将反映服务项目的生产环境。在 Facebook 的集群管理系统 Twine 上,它以一种标准的形式表述了所有的服务项目。但,它也可以透过编程的形式对这些模块进行检查和。在进行特定修改之前,试验可以检查和环境,并检查和它的合理性,然后将它返回到 Twine 进行实例化。当服务项目所有者在某些情况下须要干预时,比如两个服务项目须要特殊的硬件,而在默认的试验机池中不存在,则健全检查和负责通知服务项目所有者。特定的修改试验包括将试验实例与生产系统隔离,减少服务项目的资源需求以节省容量,和其他较小的修改。

隔离是独立自主试验中两个特别重要的元素。这是因为试验基础建设决定了采用哪些输出。不过,无论它的选择怎样,试验一定不能产生过敏反应。举例来说,有一种情况是,两个试验中的 API 失败的数据到达了监控基础建设,它错误地认为故障是来自生产系统。结论,它产生了虚假的警报。

虽然从技术角度来看非常简单,但将试验环境与基础建设的其他部分完全隔离常常会导致试验失败。正因为如此,他们必须采用更细粒度的方法:

他们可以透过已知的只读流量。他们让服务项目所有者可以为安全目标设置容许列表。他们将所有标准 PRC 流量都重新路由到通用演示中,这样就可以演示任何服务项目并返回虚假的值。他们禁止所有其他网络请求。

这样,他们就可以在两个安全的试验Escrow三分之一的服务项目,而不须要人工干预。

在实施隔离时,他们结合了两种方法:一种是细粒度的应用级隔离,另一种是粗粒度的网络级隔离。他们对 RPC 调用了应用级隔离。这可以基于调用的 API 来阻止连接。在 IP: 端口的粒度级别,网络级隔离是工作的。一般情况下,他们采用它容许连接到诸如 DNS 等知名端口上的监听服务项目。除基于连接目的地作出决定外,隔离系统还可以根据启动连接的标识符作出决定。这样做是有价值的,因为某些标识符可以安全地采用可能不安全的 API,该隔离方法论透过在运转时检查和堆栈跟踪来识别调用者。

对隔离层的构建,他们考虑了两种同时实现方案。BPF 和 LD_PRELOAD。最后,他们决定采用后者,因为它提供更多了更大的灵活性。预加载方法论从他们的配置管理系统中检索特定于服务项目的隔离配置,并透过拦截对 libc connect、sendto、sendmsg 和 sendmmsg 函数的调用,从而相应地阻止连接。

试验输出

为深入探讨试验智能化,他们研究了现有的智能化技术。模糊试验是他们软件系统试验内部结构的自然匹配。它的动态性质非常适合经典的试验范式,而它的自动输入生成则补充了手动撰写的试验。

模糊试验的核心是一种乱数试验形式。不过,虽然它很简单,但设置模糊试验仍然须要几个手工步骤:

将须要模糊试验的标识符分割成两个独立的模块(试验目标)。与模块试验相同,典型的模糊试验是在两个相对较小的标识符模块上进行的。撰写两个模糊试验工具,负责将乱数数据生成为模糊试验标识符所需的类型,并在试验目标中调用正确的函数。保证乱数数据符合试验目标的预期约束条件。

最后一点儿须要进一步澄清。假定须要对 strlen 函数进行模糊处理,该函数期望两个有效的指针指向两个以 NULL 结尾的字符串。在模糊处理生成输出时,它须要确保所有输出都是指向 NULL 结束的字符串的有效指针。否则可能会导致标识符崩溃——并不是因为在标识符中存在 bug,而是由于调用者参数与被调用者期望之间的不匹配。这些期望(也称为 API 契约)常常是隐式的,因此须要手工完成。

在结合了模糊试验和软件系统试验时,他们可以同时实现上述手工步骤的智能化:

他们根据前面描述的生产环境来创建环境。这使得他们无需手工划出标识符,而这些标识符必须进行试验。这要归功于 Facebook 的 Thrift RPC 架构,那个服务项目的 API 契约是显式的,可以透过编程的形式获得。Thrift 提供更多了两个接口表述语言,它具有反射特性,可以枚举 API 及其参数。而且,参数类型和其属性也可以像需求一样被递归地检查和。基于这些信息生成相应的值之后,就可以动态地实例化每个参数。用两种方法来采用那个能力。第一,构建所试验服务项目的输出。其次,自动演示服务项目的倚赖亲密关系,并将其返回默认值。这样就可以用正确的格式自动生成乱数数据,自动创建模糊控制。最后,两个服务项目可能不期望接收到网络上的输出。这样可以消除由于输出值和服务项目预期不匹配而导致崩溃的所有机会,这意味着所有遇到的崩溃都会指向实际的 bug。

构建输出最简单的方法是为每个数据类型乱数地选择合适的值。这种方法自动提供更多了两个试验基线,因此具有确定技师在手工内部结构设计试验时可能忽略的极端情况的优势。对每两个数据类型,像 MAX_INT 这样的极端情况值,可以增强这一过程。

乱数(和模糊)试验的弱点是,当输出的有效性涉及复杂的约束时,例如校验和,它是无效的。单纯的模糊试验难以在这种情况下找到有效的输出。除了任何初始的输出验证外,它不会继续执行服务项目方法论。

他们采用请求记录来克服这一问题和提高独立自主试验的效率。对访问生产服务的一小部分请求,他们定期记录,对这些请求进行“清理”,并将它们提供更多给试验基础建设。在这种情况下,试验不会以完全乱数的输出运转,而是记录的请求会有不同程度的变化。这种方法的基本原则是,所得到的的输出将保留足够的原始请求的有效内部结构,以继续执行“深层路径”,但也有足够的乱数性,可以锻炼这些路径的极端情况。

在纯粹的模糊处理的另一端,他们采用记录的请求,而不改变它。它证明,新版本的服务项目能够在没有异常行为的情况下处理上一版本的流量,就像经典的金丝雀试验一样。以记录和重放的形式解决了那个问题,好处是不须要独立的试验基础建设,也不会影响生产系统。

试验 Oracle

I 同时实现,这表示存在 SQL 注入漏洞。Python 语法错误(SyntaxError)异常也是相似的。本例中,模糊器可以修改传递给 eval 的字符串,并指向可能继续执行的任意标识符。

部署与经验教训

独立自主软件系统试验的部署策略包括两个步骤。首先,他们开始在后台为尽可能多的服务项目运转试验,而不须要服务项目所有者的参与。这样,他们就可以知道有什么机会可以改善,和报告问题的最佳形式。下一步,他们引导服务项目所有者选择在部署其新版本服务项目之前自动运转该试验。他们选择了 opt-in 模式,因为试验失败须要立即采取行动来解除服务项目的部署管道。他们现在从第一步进入第二步。

在第一步中,透过应用于模糊软件系统试验的隔离,他们可以安全、自动地对大约三分之一的 Facebook 的 Thrift 服务项目进行模糊试验。那个模糊试验发现了超过 1000 个 bug。对每两个 bug,他们都给服务项目所有者分配了一份报告。余下的三分之二的服务项目都具有非标准的设置,或者具有严格的权限,使得他们不能重用他们的生产工件,或者由于他们继续执行的严格隔离而失败。在这一步中,他们只透过 bug 报告与服务项目所有者接触。

透过这一过程,他们学到了一些东西。首先,透过他们的试验,他们发现在隔离试验环境方面有许多机会可以改进。因此,他们支持采用更细粒度和可扩充的方法来标记只读 API。此外,他们还继续考虑怎样为软件系统试验环境提供更多两个一流的抽象化,并透过可组合性提供更多重复采用试验环境的能力。

第二,他们学到了,向服务项目所有者提供更多尽可能多的有关他们检测到的 bug 的信息是非常重要的。与模块试验相比,在软件系统试验失败的情况下,调试本来就很困难。虽然堆栈跟踪有助于了解崩溃,但有效的调试还须要对崩溃的服务项目及其采用的库有很好的理解。他们注意到,从总体上看,违反 API 契约要比崩溃更容易调试。

第三,他们注意到,乱数输出使得解释 bug 变得更加困难,技师们也更难找出 bug 的根源。透过更广泛地采用记录的流量和提供更多大多数形式良好的输出,他们可以解决这一问题。有些情况下,技师可能会认为,给定乱数输出,服务项目可能会透过抛出未声明的异常或崩溃而破坏其 API 契约。建议反对这一做法,而应依靠全面的输出验证。

最后,了解模式试验的有效性也非常重要。迄今,他们仅将发现的 bug 作为有效性度量,现在他们开始测量整个服务项目覆盖范围。他们希望这能让服务项目所有者深入了解服务项目的哪些部分须要额外的试验。责任编辑也指出了他们可以对软件系统模糊试验基础建设进行改变,以增加未来的整体覆盖。

作者简介:

Paul Marinescu,Facebook 研究科学家。

未经允许不得转载:百万个冷知识 » Facebook 如何做大规模服务的自主测试(Facebook主页成效分析)
分享到: 更多 (0)

百万个冷知识 带给你想要内容

联系我们