OSDI论文背后的真实行业工作之旅——数百万服务器的全球容量管理

2020年,作为Meta(前脸书)的一名新员工,我非常幸运地被委以这样一个问题:我们应该如何管理公司数百万服务器规模的全球服务器容量。尽管我在容量管理方面没有任何背景知识,但我还是被委托从事这项工作。尽管如此,这项工作不仅成功地投入生产,而且我们还在OSDI’23上发表了一篇题为“具有流量的全球容量管理“这篇帖子分享了我个人的故事轶事和半技术性的内容,并试图通过快速迭代改进和利用强大的团队合作,对超大规模公司的实际行业工作进行一些了解。

我于2020年1月加入Meta,此前我花了15年多的时间研究多家公司和行业的基础设施问题,包括谷歌,推特、和GRAIL公司。我一直对驱动我们现代世界的软件基础设施着迷,我被Meta吸引是因为它独特的文化、巨大的规模,有时甚至是非正统的技术方法:例如,Meta投资于大型软件整体当该行业坚定地朝着另一个方向发展,并开创了建筑业开放式硬件平台.

在我的职业生涯中,我开始相信两个大想法,这两个想法推动了我的职业选择以及我选择追求的具体项目:

  1. 规模带来了独特的挑战。在大范围内,现有的解决方案往往会出现问题,需要新的方法才能取得进展。规模也会改变基础经济:突然间,追求相对较小的收益是有意义的,而这些收益需要高度的技术成熟度。(有趣的是,这与自然世界类似,在自然世界中,从一个尺度导出的自然法则并不容易适用于另一个尺度。)
  2. 人员和流程与技术选择同样重要,有时甚至更重要大规模解决棘手的挑战很少是一个天才想出解决方案的问题。相反,它需要一群有才华的人一起工作。

我们的关于通量的最新论文,在OSDI’23上发表。我相信Flux是Meta这样一家公司研发的典范。它强调了我们面临的巨大规模和基础设施复杂性如何导致新的挑战,以及如何应对这些挑战需要我们开发新的解决方案来解决潜在的业务问题。最后,解决这些问题需要一大群人一起工作来定义问题,集体讨论解决方案,并执行和迭代生成的系统。

通量的开始

故事开始于2020年2月,当时我正从Meta的训练营毕业。训练营是我们为期一个月的强化计划,为每一位新员工提供培训。它将带领您快速了解Meta的技术、工具和文化,为您提供在Meta应用技能所需的工作知识。 

在我参加了大约一个月的训练营之后,考希克·维拉拉哈万建议我到西雅图来讨论一个有趣的问题:我们的硬件订单变得越来越复杂,我们需要找到一种简化它们的方法。这太令人困惑了!由于我以前没有容量规划方面的经验,当时我真的不明白为什么会这样。难道你不应该订购所需的硬件并立即开始吗? 

西雅图的那一天非常迷人。我发现硬件订购确实是一个复杂的问题,根本不是我设想的简单任务。这是因为,从根本上讲,硬件订购是一个高度受限的优化问题。物理空间和电源可用性方面的限制限制了在任何给定的数据中心区域中可以订购多少硬件。此外,硬件更新过程(包括更换老化的硬件)增加了更多的限制。这些刷新会暂时降低数据中心的可用容量,因为它们是用来替换现有硬件的,这些硬件必须先退役才能为新机架腾出空间。此外,硬件更新必须考虑到双倍占用率,即服务从旧硬件迁移到新硬件的时间段,从而使所需的容量占用暂时翻倍。

数据中心容量被划分为地理上独立的数据中心区域,这一事实使这一切更加复杂。服务部门通常倾向于在特定地区扩大其容量足迹,这给硬件订购问题增加了额外的限制。此外,服务形成了一个依赖关系图:我们不能在不考虑其下游依赖关系的情况下单独向服务添加容量,而下游依赖关系又可能需要额外的容量来处理更大容量的上游服务所增加的负载。

因此,我们发现自己有一种棘手的问题。一方面,我们基础设施的规模和复杂性不断增加,导致了容量订购的复杂性。另一方面,服务业已经开始依赖于在特定区域实现其能力。结果是,每个容量订购周期都需要我们的容量规划师和服务所有者之间进行复杂的谈判过程,在这个过程中没有人满意。由于空间和功率的限制,有时需要我们完成区域外的硬件刷新,这使得情况更加复杂。换句话说,我们需要服务重新分配其容量足迹,以便实现硬件更新。

解开这个结需要我们找到一种方法来更好地将服务放置与容量规划分离开来。

回到2020年2月的会议。考希克邀请了一些从事容量管理不同方面工作的人员。我们的产能规划主管出席了会议,我们车队管理小组的一些主管也出席了会议。这个想法是利用我们的综合知识集思广益,为当时被称为“区域化问题”的问题找到解决方案。 

考希克首先强调了我们有两个重要的拼图块:

  1. 首先,我们的基础设施即服务(IaaS)项目进展顺利。IaaS从根本上说是要摆脱管理自己机器的服务,而是通过一小部分共享池来管理我们的整个车队。这使我们转向了一种模式,在这种模式下,我们可以不再规划单个服务,而是规划容量池。
  2. 我们管理Meta的经验灾难恢复这些努力表明,我们可以在各个地区安全地重新分配流量,而且我们的大型服务依赖关系图在实践中是可以管理的。 

然而,除此之外,我们什么都没有!我们花了一天时间1)分享背景;2) 定义成功的结果;3)制定一些近期目标。这种结构清楚地说明了在我们这样的组织中工作是如何完成的:

  1. 由于我们在一个由大型团队组成的复杂环境中运作,沟通技术和组织环境是成功解决问题的重要组成部分。没有人有完整的想法,因此我们必须创建强大的共享上下文空间,才能成功地解决这些问题。
  2. 如果我们没有共同的目标感,我们可能无法取得进展,因为我们都朝着不同的方向前进。
  3. 具体的短期目标迫使我们找到一种方法,迈出下一步,朝着我们的目标取得具体进展。除了更接近于解决问题本身之外,这样做还常常带来更多的清晰度。

当天结束时,我们对所面临的问题有了更清晰的认识,但只是对如何解决这个问题有了一个抽象的想法。我们为自己设定了一个雄心勃勃的目标:虽然本季度的硬件订单已经完成,但距离下一个硬件订单只剩下一个月左右的时间。我们能否快速下“硬件优先”订单,要求我们在那时也充分了解服务放置问题,以便我们能够放心下订单?

初始硬件订单

接下来的一个月是与同一组人一起紧张地工作,每天在同一个房间里聚会6个小时。(我们把剩下的时间都花在了模型、电子表格和代码上。)在我们继续工作的过程中,我们发现了问题的许多新方面,并且我们慢慢地融合到了一种方法论上,以确定如何在这个新世界订购硬件。 

至此,我们将问题细分为三个部分,每个部分都可以独立解决。 

  • 问题1:这是硬件订购本身:我们向池中订购了多少硬件,以及订购到哪些区域? 
  • 问题2:这就是服务放置问题:给定硬件分布,我们如何以最佳方式将容量分配给服务?如何分配产品流量? 
  • 问题3:这就是我们所说的执行问题:给定一个特定的布局计划,如何重新分配流量和服务来执行该计划? 

(Flux论文主要关注我们如何解决问题2和3。)

由于硬件订购截止日期即将到来,我们首先关注的是订购问题。我们设计了许多解决方案的原型,将Excel电子表格与Python笔记本混在一起,有时甚至还会编写一些C++代码。我们的目标是建立模型,帮助我们更好地理解问题,并揭示我们尚未考虑的方面。我们主要依赖现有的数据集,因此必须插补大量数据。(这样做有助于为我们的指标收集路线图提供信息。)我们还会见了不同的服务所有者(我们订购的容量的接收者),以帮助验证我们正在制定的容量分配类型,看看他们在实际中是否可行,因为他们了解他们所操作的系统。

我们最终使用算法、约束求解器和手动调整的组合,得出了一组硬件顺序。然后,我们与两个服务所有者一起验证了这些订单。我们还使用了一些我们开始构建的初始服务放置模型。这些模型帮助我们验证硬件订单是否可行:我们是否可以有效地分配订购的硬件?在第一次迭代中,我们构建了一些简单的、特别的模型。订单下达后,我们花了大部分时间了解如何改进这些模型,并使用它们将容量直接分配给服务。

准备着陆

我们使用问题1的初始解决方案进行硬件订单。订购的硬件将在大约6个月内到达,给我们相对较少的时间来解决问题2(服务放置)和问题3(计划执行)。

我们很早就决定使用我们的灾难恢复runbook系统用于我们的首次执行。这些运行手册被设计为一种人机交互的自动化系统,将自动化与人工操作、反馈和验证相结合。虽然它们是为其他目的而设计的,并且用于比我们预期的Flux所需的复杂度更低的计划,但它提供了一个很好的起点,因此我们可以将精力集中在服务安置上。 

第1课:试着一次只处理系统的一部分。使用现有的无目的执行系统可以让我们将大部分精力集中在解决相对较新的问题上。 

我们知道,我们的模型需要捕获每个服务需要多少容量,以及服务依赖关系如何影响放置。我们的模型还需要一个独立变量:我们可以使用它来影响容量布局。我们意识到我们可以利用交通管理系统控制产品流量(例如脸书、WhatsApp、Instagram)在我们地区的分布方式,我们可以将所有服务的服务容量分配建模为产品流量的函数。直觉如下:最终,对服务的需求是由其调用者驱动的。这些呼叫者又是服务,其需求由呼叫者驱动。该链终止于直接接收用户流量的前端服务(例如,web服务器)。这也适用于我们控制其全球需求分布的内部服务。例如,XFaaS公司是一个全球无服务器平台。我们可以通过影响请求在不同区域排队的方式来控制其需求分布。

因此,产品流量分布成为我们模型的自变量。那么,我们可以直观地将分配给服务的容量分解为代表每个产品的各个部分。例如,像memcached这样的共享服务可能会细分为60%的Facebook、20%的Instagram、10%的WhatsApp和10%的XFaaS。然后,我们可以将此总体细分与观察到的跨区域流量分布结合起来,来解释服务的容量足迹。

将容量使用归因于三种产品:Web产品、移动产品和异步。对于区域A中的索引服务,注释“[40%WP,60%MP]”表示索引服务的容量消耗的40%和60%分别归因于网络产品和移动产品。请注意,虽然需求属性是相对的,但容量使用基线是根据绝对容量定义的。

另一个建模挑战是:我们使用哪些单位来表示容量?不同的服务不仅使用不同的硬件类型(例如,CPU为主、DRAM为主、加速器、闪存、HDD等),而且每个服务都可能有不同的瓶颈资源(例如,一些服务可能被CPU阻塞,其他服务被DRAM阻塞),这也会影响我们为服务建模容量的方式。在第一次迭代中,我们决定通过指定每种机架类型的功率容量(瓦特)来简化。虽然它没有捕捉到服务容量需求的所有细微差别,但电源是使总容量正常化的有用方法,它代表了我们数据中心占地空间的实际可用性。我们的论文详细介绍了我们如何通过将瓶颈资源纳入我们的服务放置模型,在以后的迭代中解决这个问题。

在我们为到达数据中心的硬件做准备的过程中,我们努力将多个数据集组合在一起,进行后处理,偶尔手动调整它们。我们“分散”了我们的团队,对这些基线数据的不同方面进行研究。最终,我们将它们结合在一起Python笔记本这使我们能够灵活地迭代数据和算法,同时为我们的实验和最终的生产计划提供了再现性。 

一旦我们有了一个满意的基准,我们就构建了一个贪婪的算法,为包含订单和硬件更新的每个服务分配容量。这个算法很简单,但很容易理解:我们可以很容易地理解分配是如何进行的,反过来也可以很容易向接收容量的服务团队解释这些。贪婪算法的主要缺点是难以实现更复杂的目标函数。

第2课:逐步引入复杂性。即使这会导致不太理想的结果,但首先做简单的事情可以帮助您更好地理解问题,并了解什么构成了适当级别的解决方案复杂性。

一旦我们以这种方式建立了分配计划,我们就直接与服务团队合作来验证和调整它们。由于这是一个全新的模型,也是一种全新的方法,甚至可以在Meta实现容量分配,因此我们觉得需要手动验证才能轻松执行。我们还希望确保不会对通过此过程获得容量的团队施加过度的操作复杂性。

第一个执行周期

一旦我们制定了产能计划,并得到了相关团队的批准,我们就做好了执行的准备。使用我们的runbook基础设施,我们与运营项目经理团队合作,帮助执行计划。他们与多个团队合作,在其增加的地区扩大其容量分配,帮助团队应对交通变化,并最终放弃其分配减少的地区的容量。

这个过程是高度手动的,我们还没有安装自动化系统,但也有很高的教育意义。由于这是我们第一次在我们的基础设施中协调如此大规模的容量变化,我们发现了许多我们没有预见到的问题,并且我们在模型中发现了我们的模型或基线没有很好地捕捉到的边缘情况。这有助于我们更深入地理解问题,并指导我们不断努力实现自动化执行。

第3课:首先,做不可缩放的事情.如果没有我们的第一次手动执行,我们将构建错误类型的自动化。手动执行教会了我们真正的问题是什么,以及如何在后续执行周期中最好地部署自动化。

虽然我们成功地执行了第一个布局计划,但我们的经验告诉我们,自动化将是支持任何大规模计划的严格要求。我们还遇到了一些团队的实例,这些团队打算以新的方式使用能力,而不是将其编入我们的模型中。这有助于确定如何发展我们的建模方法,并推动建立某种能力合同在我们的能力组织与其客户之间:如果我们不能将服务如何使用其分配的能力背后的意图编纂成文,那么我们将很难继续推动提高自动化程度。 

成熟的系统

到2021年初,我们已经:

  1. 使用新流程订购硬件,该流程(主要)与服务放置分离。
  2. 构建了一个容量放置基线这捕捉到了服务能力分配和前端产品流量分配之间的关系。
  3. 通过算法计算出最佳利用订购硬件的服务放置计划。布局计划考虑了服务的相互依赖性产品流量根据容量可用性。
  4. 使用我们现有的灾难恢复runbook系统执行计划。

现在是时候将这些部件组装成高度自动化的端到端系统。我们现在有了足够的清晰度来更好地并行化我们的工作:我们理解了系统组成部分之间的边界,我们可以在这些组成部分中或多或少地独立工作。 

模型基线在我们的初始原型中,我们从大量基线和专家知识中估算了服务依赖性数据。我们转而使用RPC跟踪直接测量这些依赖性。这需要与负责RPC跟踪系统的团队以及各种服务团队合作来验证模型。我们将RPC跟踪数据与基线容量数据结合起来,将服务需求数据转换为模型所需的容量足迹(cs,r)。

安置规划。我们放弃了贪婪求解器的方法,转而制定一个混合整数优化程序(MIP),我们可以将其应用于商用优化器这使我们能够实现更复杂的优化目标,并保证针对这些目标的最佳性。虽然很难对贪婪求解器提供的结果进行推理,但额外的表现力和优化充分证明了复杂性的增加。

自动执行。我们为我们的安置计划构建了一个工作流执行引擎。该系统能够将自动化与人工操作无缝结合。当服务未与我们的容量自动化系统集成时,我们的工作流引擎将通过提示操作员执行等效操作来协调执行。对于使用我们的容量自动化系统的服务,工作流可能会要求人工操作员批准结果。这是在我们的模型无法为服务提供足够高质量结果的情况下使用的。

数据作为接口。有一个设计原则值得强调:所有这些系统都通过“普通旧数据”接口,形成一条管道。例如,我们的模型基线是一个输入布局规划算法的数据集。布局规划阶段输出另一个包含布局规划的数据集。最后,我们的执行系统将该计划转换为要执行的操作图。这种方法有许多重要的优点:

  • 这意味着我们可以单独迭代每个组件。例如,我们可以冻结基线输入,并在计划器中调整各种优化参数。
  • 我们可以存储这些数据集,以便以后用于复制管道的不同部分。这有助于我们调试后来才出现的问题。例如,我们可以很容易地调试只在执行阶段出现的计划缺陷。
  • 它允许我们通过维护每个数据集的版本来跟踪每个计划的沿袭。这有助于我们了解其潜力范围他们提出的问题。例如,它允许我们确定哪些计划可能受到基线数据集中缺陷的影响。

我们也将这一原则的使用扩展到了执行。我们建立了一个简单的容量控制平面它被用作我们的工作流执行引擎和底层容量自动化系统之间的接口。执行引擎存储容量意图到共享数据库中。容量意图包括扩大规模(指地区内的服务),缩小规模(指地区内的服务),以及产品流量变化(地区之间)。每个意图都包含估计的执行时间,并包含WAITING、READY或COMPLETE状态。只要可以安全执行,工作流引擎就会将意图的状态从READY更改为READY;负责意向的容量自动化系统在完成后将其状态更改为“完成”。

此容量控制平面用于两个目的:

  1. 它将执行的编排与其机制解耦。因此,我们可以支持多种类型的容量自动化。
  2. 它提供了预期容量变化的权威时间表。除Flux之外的系统也会编写这样的容量意图,而Flux反过来会调整其基线预测未来的产能变化。同样,我们的容量自动化系统使用预期流量变化的记录,在流量变化之前正确调整服务的容错大小。
第4课:通过普通旧数据解耦系统.数据易于存储、操作和推理,这是首要的清晰的通过以这种方式构建我们的系统,我们可以很容易地对每个组件进行隔离推理,并用简单的基础设施支持我们日益复杂的工作流。

我们现在有了一个基本的系统。它端到端工作,对许多服务实现了合理的自动化。现在是迭代改进的时候了完整性质量。我们研究了如何最好地衡量系统的性能,平衡技术性能(您将在系统论文的评估部分中看到的度量)与“产品性能”(即系统对其客户的工作情况)。在项目的早期阶段合并度量可以让我们创建一个重要的正反馈回路:度量暴露了系统性能不够好的地方。这通常从查看高级度量开始,然后将其分解为组成部分。选择最大的贡献者,并努力改善它。冲洗,重复。 

我们还使用这些测量值设置项目级目标这使得各个子团队(我们现在全职工作于Flux的人数略多于10人)想出了如何为总体目标做出贡献。这是管理大型复杂项目的好方法。

第5课:衡量什么是重要的找到一种方法,在早期阶段将度量纳入项目。用这些来指导执行和成熟。

通过专注于改进这些指标,我们最终能够显著提高可用于执行的自动化程度(有关详细信息,请参阅论文),并相应地减少了执行时间,从而提高了总体容量效率。

今天的流量

虽然Flux现在已经投入生产三年多了,但世界却没有停滞不前。在Flux被用于管理Meta的容量期间,我们经历了供需冲击,以及AI投资的大幅增加。对这些现实的响应将我们的能力规划和管理系统推向了极限,而Flux在我们做出良好响应的能力中发挥了核心作用。 

与此同时,Flux无疑是一个改装的现有容量管理制度:通量模型(观察)容量是如何使用的,并通过建立在现有容量自动化系统之上的自动化来影响容量的分配。

这种方法的局限性在于,我们的基础设施和使用该基础设施的服务之间只有一个微弱的“合同”概念。也就是说,如果一个服务改变了它的区域化行为,Flux将继续接受这一有效的改变,并相应地更新其模型。Flux假设当前容量基线构成基本事实关于如何运营我们的服务。

随着时间的推移,我们意识到,为了更可预测地运行我们的基础设施,并能够提供更长的规划范围,我们需要将Flux的概念提升为容量合同例如,服务可以通过指定容量的用途来“购买”容量跟随产品流量。现在,基础设施和服务之间的职责划分更加清晰,我们可以在规划期间做出强有力的假设。这也解决了Flux的一个主要症结,正如本文所概述的那样:模型可以是错误的,他们经常这样。

通过将区域化约束编入容量合同,我们使用Flux执行我们可以判断Flux是否能够在需要的地方交付容量(根据合同)。然后由服务所有者正确使用该容量。在过去,如果Flux没有提供足够的容量来支持某个地区的服务,那么Flux自然会被视为原因这是因为它的容量模型没有准确地捕捉到实际需求。有了产能合同,我们反而声明容量模型是什么,并要求服务指定他们希望其容量遵循的产品流量实体。 

第6课:将模型编入合同.管理容量总是需要对其使用进行建模。合同由容量管理系统和使用它们的服务提供的模型复杂性总是会变得棘手。

全局抽象。Flux旨在将容量管理扩展到10多个数据中心区域。我们现在正在运营20多个数据中心区域,虽然Flux(及其后续系统)解决了许多重要的容量管理问题,但也存在服务管理如此广泛的部署所产生的问题。例如:如何跨20多个地区协调服务的部署?如何将流量平衡到跨这些区域部署的服务?您如何管理共享服务的副本?服务应该如何管理20多个地区呈现的无数相关和不相关故障场景?只有当我们开始将地区视为“牛,不是宠物”.

我们的答案是我们称之为努力全球抽象。这项工作的目的是从我们的服务管理工具词汇表中删除“区域”。服务不是部署到N个区域,而是通过单个控制平面全局部署。控制平面负责管理如何跨区域分布服务作业、如何复制数据、如何路由流量以及如何准备和管理故障场景。至关重要的是,服务所有者原因我们的控制平面负责管理服务的复制、路由和部署方式。

我们选择这个名字是因为我们的目的是引入新的,全球的摘要。例如,我们希望根据延迟目标管理服务路由,而不是通过管理特定区域之间的流量路由。同样,我们管理全球容量容差而不是每个地区一个。共享服务是根据复制预算和一组灾难场景进行管理的。 

提供全局抽象还使我们能够支持未部署到每个区域的服务(其客户端可以承受跨区域调用引起的额外延迟)。例如,一些有状态服务发现将数据复制到每个区域是浪费的;在某些情况下,我们还受到某些地区硬件可用性的限制。支持此类部署还需要我们在布局模型中编纂延迟预期。

Global Abstractions提供了绝佳的机会,可以同时简化我们的基础架构产品,同时在管理基础架构的同时提供更多优化机会。关于这些努力,我们很快就会有更多的话要说。

尾波

容量管理是:1)重要;2) 技术上坚硬的; 和3)在系统社区中被忽视。我们认为在这个领域有很多机会,我们对Flux的介绍实际上只触及了这个丰富问题空间的表面。

多亏了CQ唐提供许多建议和编辑;还有我所有帮助Flux成为现实的同事们。

关于作者:Marius Eriksen是Meta核心系统组的软件工程师。他在那里的工作包括容量管理、服务管理、控制平面基础设施和人工智能基础设施。

免责声明:本博客中表达的任何观点或意见都是个人的,仅属于博客作者,不代表ACM SIGOPS的观点或意见。

编辑器董都(上海交通大学)