我们已经达到了分布式计算无处不在的地步。内存应用程序数据大小正在超过单台机器的容量,因此需要将其分区到集群中;在线服务具有高可用性要求,这只能通过将系统部署为多个冗余组件的集合来实现;高持久性要求只能通过数据复制来满足,有时甚至跨越广阔的地理距离。虽然可以说,采购必要的硬件(这要归功于公共云的普及)以及使用各种工具(从 Kubernetes 等集群编排器到函数即服务等较新的范例)来部署分布式应用程序从未如此容易,但构建正确且高效的分布式解决方案在很大程度上仍然是一项个体化的工作。
对于任何分布式程序要正确运行,都需要解决一系列基本问题;与此同时,这些问题涉及分布式计算的各个方面,这些方面代表了与应用程序程序员习惯于实现的单节点程序最显著的背离,并且可能是最难正确解决的。在其中一些方面犯错——例如在部分故障存在的情况下进行通信和分布式操作的协调,或者远程访问和修改共享数据——可能会影响系统的正确性;而另一些方面——例如适当的数据分区和放置——不会影响程序结果的有效性,但如果搞错,可能会对系统性能产生灾难性影响。
似乎希望能够将这些问题与用户应用程序隔离,并在基础设施层面解决它们,以便运行在分布式计算底层之上的各种程序都可以从中获益。可以说,Hadoop MapReduce 和 Apache Spark 等大数据框架是迄今为止最成功的尝试,它们使渴望处理大数据的程序员能够利用机器集群的力量来加速大规模计算。它们的特定领域编程抽象将应用程序程序员与跨主机平衡计算和在主机之间移动数据的机制以及管理主机故障隔离开来。然而,它们的领域特定性使得它们不适用于大型应用领域,例如长期数据存储或 Web 应用程序后端。
更典型的情况是,在实践中,分布式系统以各种子系统的组合形式出现,正如现代面向服务的架构所说明的那样。类似于 Unix 模型,功能是在“进程”的粒度上组合的——大型程序是通过采用较小的程序(例如 Cassandra 或 etcd 等数据存储,RabbitMQ 等消息代理等)构建起来的,这些程序旨在孤立地解决特定问题,并通过引入适当的管道供应用程序使用它们并在它们之间进行协调来组合它们。这种范例为程序员带来了主要的权衡:为了换取对系统工作原理细节的更多控制权,他们现在暴露于分布式系统陷阱的全部广度。
一些最新的系统试图在这两个极端之间取得平衡,努力在不不必要地限制可以在其中合理表达的程序种类的情况下,提供大数据框架的易用性,并且他们这样做的方式是专注于促进分布式计算的常见模式。其中一个例子是 Temporal,9 一个分布式执行平台,其中用户程序被表示为各个步骤的工作流,这些步骤使用熟悉的 async/await 范例进行交互。程序员使用 Temporal 的 API 来表达他们的工作流,并且他们可以保证这些工作流在出现任何类型的故障时都能正确运行并完成。
Temporal 的核心是其持久工作流抽象,它捕获了响应计算请求所需的步骤序列;在某种意义上,工作流抽象是用户编写程序的针对目标,但它有效地将用户与执行细节隔离开来,执行细节完全由 Temporal 平台决定。Temporal 本身并不关心工作流的每个步骤中运行的确切代码;它唯一需要了解的细节是,如果遇到故障,它被允许做什么。
正如其中一些系统所证明的那样,正确的抽象选择,例如 Spark 的弹性分布式数据集10 或 Temporal 的持久工作流,可以实现业务逻辑与分布式结果编排的清晰解耦。通过代表用户处理编排和通信细节,像 Temporal 这样的系统可以降低入门门槛,并允许应用程序程序员利用计算机集群,而无需成为分布式计算专家。与此同时,这种关注点分离仅仅是帮助程序员驾驭分布式计算领域的第一步(必要的)。我们应该使用上述解耦作为基础,从程序员的工作中消除的不仅仅是协调方面的考虑(例如,共享数据一致性)。
为此,重点应放在提供与语言无关、可重用的抽象,以在用户最少参与的情况下促进正确的分布式结果。语言独立性是一项关键要求,因为它允许最大化可以从这个想象的基础设施中获得的效用。这项要求引导我们从编译器研究中寻找灵感。
在过去的 15 年中,由于 LLVM 等项目的存在,以及更具体地说,能够将截然不同的语言编译成统一的 IR(中间表示),编译器工具链的其余部分以一种与生成它的前端语言无关的方式对其进行操作,因此探索新的编程语言和范例的兴趣重新燃起。这个 IR 完全捕获了用户程序的细节,但它是为理想化的、不存在的机器这样做的;编译器可以自由地在这个封闭的表示中根据内部规则集应用有时是激进的转换和优化,并且随后可以将针对这个理想化虚拟机优化的程序翻译成目标架构的具体汇编代码。
如果数据中心被认为是计算机,1 那么应该问这个问题:是否存在一个理想化的 IR 用于它?这个 IR 必然不同于传统编译器使用的 IR,因为(理想化的)分布式计算机的“基本”操作与单 CPU 的操作不同。例如,单机程序最重要的方面之一围绕内存的加载和存储展开,而在集群级别,它们围绕何时以及如何发生跨机器通信展开。
作为这个 IR 的基础,我们可以考虑分布式数据流,其中大规模程序被表示为有向无环图,其中每个节点代表一个单节点功能片段(例如,函数调用),称为运算符,边代表这些计算片段之间的数据依赖关系。通过这种方式,所有与分发相关的关注点都隔离在运算符之间的边上。核心业务逻辑是应用程序程序员的领域专长,它与分发无关;沿边发生的事情可以是编排和分布式执行层的管辖范围。
本地代码和分布式代码之间的这种分离鼓励我们设想一种基础设施,该基础设施将嵌入在用户程序中的分布式交互转换为中间分布式数据流表示,然后将其“编译”为分布式计算的具体编排。程序在这个 IR 中的表示捕获了程序员的意图——数据如何在系统中流动以及它所经历的转换——同时在运行时留有余地,以便在放置和网络交互方面做出具体决策。
用不同语言编写的组件可以相互引用和使用,它们的交互修改和扩展了底层数据流图。这种 IR 的存在还将使统一的运行时成为所有集群范围计算的计算基础。本文通过重点介绍这一研究方向的两个实验性系统,突出了在这种模型下预期的某些好处。
本节着眼于两个积极的学术研究项目,旨在通过分布式计算的高级表示,将应用程序程序员从机械的分发细节中隔离出来。第一个这样的项目是 Hydro,7 这是加州大学伯克利分校开发的一个语言堆栈,旨在为用多种编程语言编写的分布式程序提供一个通用的执行底层。第二个项目是 Magpie,这是一个新的分布式单级存储和运行时,正在加州大学圣克鲁斯分校开发。
Hydro 项目由一个编译器堆栈组成,旨在将用多种语言编写的分布式程序翻译成统一的、分布式的 IR,该 IR 可以由 Hydro 运行时执行。在该项目设想的未来中,程序将使用程序员选择的语言编写,利用 Hydro 的库和 API;Hydro 编译过程的核心是多个级别的中间表示,每个级别都有不同的用途。
第一级 IR Hydrologic 是一种声明性语言,它捕获目标分布式计算的高级逻辑计划;Hydrologic 程序表示程序员关于应用程序数据如何在系统中转换和传播的意图,但省略了具体的运行时细节,例如主机之间的通信或数据放置和复制策略。
然后,Hydrologic 程序被转换为第二级 IR,称为 Hydroflow——Hydroflow 程序在语义上等同于它们起源的 Hydrologic 程序,因为它们产生相同的结果,但旨在成为可以由 Hydro 运行时执行的单线程、单节点程序。这个基本的 Hydroflow 表示随后被编译过程的最后一步使用,最后一步的工作是将单节点 Hydroflow 程序翻译和优化为可能的多主机异步数据流程序。这个最终配置和优化步骤考虑了用户以声明性形式指定的高级目标(例如,程序应容忍的最大主机故障数或每个端点延迟服务级别目标),这些目标用于发现用户程序的适当配置,然后可以将该配置部署在集群上并由 Hydro 运行时执行。
在 2023 年的一篇论文中,Hellerstein 等人6 通过引导读者完成 Dynamo 论文4 中臭名昭著的“购物车”示例的 Hydro 实现,说明了将应用程序逻辑与分布式编排逻辑分离的力量。作为示例的一部分,作者说明了相同的高级程序如何可以转换为各种具体的分布式程序;更具体地说,在最终数据流图中,表示网络通信的边的放置位置的不同决定可能会导致客户端批处理和服务器端批处理中间购物车状态之间的差异。变体的选择取决于应用程序程序员试图驾驭的权衡——作者认为,如果程序员的主要关注点是容忍客户端故障,那么服务器端批处理是更可取的部署配置;但是,如果程序员在用户隐私和数据所有权方面有严格的要求,那么正确的选择是将中间状态隔离在用户客户端上,并且仅在用户选择时才向服务器公开信息的解决方案。
无需任何实现级别的重写即可获得具有显着不同通信特性的不同实现的能力,这是分布式程序的“逻辑计划”(编码程序员的计算意图)与程序具体部署的解耦的直接结果,程序的具体部署通过在执行时在大型分布的现实下完成所述意图的机制得到增强。今天,所有这些权衡都必须在应用程序设计时考虑,因为从一个变体移动到另一个变体可能需要复杂的应用程序重写。
虽然 Hydro 仍处于相对初期的状态,但这项研究的结果突出了将分布式系统交互提升到可以进行重写和优化的高级“逻辑计划”的力量,并为一些强大的未来指明了方向。更具体地说,鉴于分布式程序被翻译成通用表示,并且组成分布式程序端到端执行的组件在本质上成为同一程序的一部分,我们可以想象通过重写和操作底层数据流图,对整个程序、跨组件进行优化的未来机会,类似于 Chu 等人 2024 年发表的工作,该工作侧重于通过规则驱动的重写来优化 Paxos。3
Magpie 是一个分布式单级存储和运行时,其中应用程序数据被打包到对象(类似 arena 的类型化内存区域)中,这些对象驻留在全局地址空间中。程序是操作数据的函数的组合;这些组合形成一个数据流图,该图在运行时动态扩展。本文重点介绍 Magpie 如何在没有程序员干预或指导的情况下分发用户程序。(Magpie 的实现及其执行模型将在未来的出版物中更详细地描述。)
重要的是,Magpie 中的数据和代码都是可移动的。对象的结构使其能够在 主机之间透明地重新定位。2 函数是位置透明的,因为它们的实现中没有任何东西依赖于特定的放置决策,并且是分布式的,因为不允许它们进行任何形式的分布式协调。它们是对本地数据的查询和转换,保证在单台机器上从头到尾执行,而不会被抢占。此外,每个函数都在 ACID(原子性、一致性、隔离性、持久性)语义下执行,这取决于用户对数据一致性的要求。Magpie 运行时本身充当给定应用程序的控制平面和数据平面的角色。
代码和数据移动性使 Magpie 能够在执行用户代码时采取极端的后期绑定方法。前面提到的静态任务图编码了有关需要遵守的数据和控制依赖关系的信息,但它省略了具体的执行细节,例如激活站点、通信细节,甚至计算的潜在并行性;当静态图在运行时扩展,并且计算的真实数据依赖关系集被发现时,运行时会编排数据和代码移动,以便它可以按保证执行这些函数中的每一个,试图充分利用集群中的可用并行性(取决于用户程序的结构),并最大限度地减少对昂贵的分布式协调(如分布式提交)的需求。Magpie 运行时可以发挥如此有效作用的原因之一是能够在数据流图的边缘执行轻量级介入,并内省每个函数的数据依赖关系和集群的运行状态,同时完全控制应用程序的数据平面。
将任意程序提升到数据流表示意味着以前被认为完全是程序员责任的问题现在可以被基础设施完全包含和解决。用户程序可以通过自动并行化透明地扩展,这得益于内省其功能依赖关系的能力,以及事务执行模型的隔离属性。对应用程序数据访问模式的可见性对于在机器集群上扩展计算也至关重要,因为它允许动态地重新调整计算和数据的放置,从而以尊重亲和性的方式最大限度地减少组件之间的分布式协调和网络交互。这分摊了网络成本,并利用了应用程序中的时间工作集,同时有效地平衡了观察到的负载。
任务图抽象还支持强大的组合模型,超越了引言中概述的类似 Unix 的服务组合模型。在这个模型中,密钥/值存储或发布/订阅系统等基础设施组件被实现为用户级库,然后可以通过它们公开的功能接口被更高级别的程序使用。
这种模型支持已建立的基础设施的开发和重用——类似于微服务模型——但是组件之间的分离(对于组织大型软件工件至关重要)仅在应用程序代码结构中体现出来;在运行时,所有组件的功能都被翻译成数据流语言中“运算符”的明确定义的组合。反过来,这允许运行时可能将单个工作流或程序的执行完全隔离在单台机器上,从而为用户程序提供极快的无分发执行,而使用更传统的方法(如 RPC(远程过程调用))的用户程序,可能会在应用程序的关键路径中涉及不必要的网络通信。8
对数据和控制平面的所有权的好处不仅限于应用程序性能方面的考虑。对于运行时执行的任何操作,都有其观察到的效果的完整因果记录,使我们能够轻松回答关于计算如何随时间推移展开、响应用户请求或什么数据发生了变化以及修改是什么的问题。此记录可以作为强大的调试工具的基础。例如,当应用程序遇到错误时,您可以收集在调查问题出现的时间段内的所有日志记录,并将它们用作单节点确定性集群模拟器的输入,该模拟器重放日志并让用户进行时间旅行调试,以隔离违规的根本原因,而不是尝试从各种工具(如应用程序日志和分布式跟踪)合成信号来帮助您向后查找问题的根本原因,以便进一步进行故障排除。
Hydro 和 Magpie 在其价值主张方面存在显着差异。例如,Hydro 建立在最近关于诸如 单调性5 和协调避免等属性的研究之上,并寻求利用这些属性作为在编译时优化用户程序的机会。Magpie 为已转换为其编程模型的任意用户程序提供正确性和性能保证,但不尝试通过更改其结构来自动优化它们;相反,它假设用户程序的最佳部署配置无法提前知道,因此在运行时寻求优化机会。
尽管存在这些差异,但 Hydro 和 Magpie 都代表了与现有范例的彻底决裂,这些范例试图通过分布式活动协调的构造来增强传统的单节点编程;相反,它们拥抱采用新的编程模型来开发具有内置稳健性的高性能分布式程序。至关重要的是,它们都证明了为数据中心计算机派生 IR 的可行性,因为两者都采用了分布式数据流的形式作为建模任意分布式计算的主要抽象,以及这种基本抽象的潜在影响。这使得这两个系统都能够从用户应用程序中消除具体的分发问题,并促进它们的正确和高效执行。
在对为本文重点介绍的实验系统重写现有应用程序的可行性做出明确声明之前,还有许多问题有待回答,但在结尾时,让我概述一条逐步采用和评估这些系统的路径,并描述这条逐步路径如何帮助解决一个日益相关的问题,即轻松利用云中的异构计算。
Hydro 和 Magpie 都为程序员提供了他们自己的数据模型——他们控制更新的持久性,并提供持久集合库以及用户使用运行时原语实现自己的数据结构的抽象。虽然这种选择支持低延迟、内存计算以及对更新持久性的细粒度控制,但这意味着它们无法直接与外部系统交换数据,而是依赖于某种 ETL(提取、转换、加载)层。未来,这两个系统都可能受益于支持 Apache Arrow 等数据格式,Apache Arrow 正在迅速成为内存计算和数据交换的事实标准格式,也许更重要的是数据交换。对外部数据格式的支持将使 Hydro 和 Magpie 能够作为子组件与已运行的系统一起部署,并以增量方式评估其影响。
凭借这些系统的数据流模型为程序员提供的更高抽象级别,再加上对通用数据格式的支持,我预计将出现轻松利用异构计算目标的新途径。只要基础设施可以调解不同计算目标之间的数据交换,并可能应用适当的转换,用户程序就可以自由地将 CPU 计算与加速器卸载混合和匹配。至关重要的是,这种用例可以预期会说明 Hydro 和 Magpie 使用的 IR 的强大功能。特定的计算目标要求将需要成为编译器堆栈或运行时在提出系统配置或具体执行计划时必须考虑的附加约束,但涉及加速器及其类似物的操作仍然可以被视为数据流图中的另一个运算符,其语义类似于应用于面向 CPU 的程序的语义;因此,可以使用户程序溢出到任何类型的可用加速器,而无需对这些系统的底层高级数据流表示进行任何修改。
1. Barroso, L. A., Clidaris, J., Holzle, U. 2013. 数据中心即计算机:仓库规模机器设计导论,第二版。Morgan & Claypool Publishers。
2. Bittman, D., et al. 2020. Twizzler:用于非易失性内存的数据中心操作系统。在 Usenix 年度技术会议论文集中; https://www.usenix.org/system/files/atc20-bittman.pdf。
3. Chu, D. C. Y., et al. 2024. 使用查询重写优化分布式协议。 管理数据汇刊 2(N1); https://dl.acm.org/doi/pdf/10.1145/3639257。
4. DeCandia, G., et al. 2007. Dynamo:Amazon 的高可用性键值存储。 SIGOPS 操作系统评论 41(6), 205-220; https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf。
5. Hellerstein, J. M., Alvaro, P. 2020. 保持 CALM:何时分布式一致性变得容易。 通讯 63(9), 72-81; https://dl.acm.org/doi/pdf/10.1145/3369736。
6. Hellerstein, J. M., et al. 2023. 特邀论文:分布式程序编译器的初步步骤。在第五届分布式系统算法高级工具、编程语言和平台研讨会中; https://hydro.run/papers/joe-applied-2023.pdf。
7. Hydro 项目主页; https://hydro.run/。
8. Seemakhupt, K. et al. 2023. 远程过程调用的云规模表征。 https://dl.acm.org/doi/10.1145/3600006.3613156
9. Temporal 主页; https://temporal.io/。
10. Zaharia, M., et al. 2012. 弹性分布式数据集:用于内存集群计算的容错抽象。第九届 Usenix 网络系统设计与实现会议论文集; https://www.usenix.org/system/files/conference/nsdi12/nsdi12-final138.pdf。
Achilles Benetopoulos 是加州大学圣克鲁斯分校的博士生,与加州大学圣克鲁斯分校计算机科学副教授 Peter Alvaro 一起从事分布式系统、数据库和编程语言交叉领域的研究。此前,他曾在多家公司的堆栈上下游担任软件工程师数年。
版权所有 © 2024,由所有者/作者持有。出版权已授权给 。
最初发表于 Queue 第 22 卷,第 6 期—
在 数字图书馆 中评论本文
Marc Brooker, Ankush Desai - AWS 的系统正确性实践
构建可靠和安全的软件需要一系列方法来推理系统正确性。除了行业标准的测试方法(如单元测试和集成测试)外,AWS 还采用了模型检查、模糊测试、基于属性的测试、故障注入测试、确定性模拟、基于事件的模拟以及执行跟踪的运行时验证。形式化方法一直是开发过程的重要组成部分——也许最重要的是,形式化规范作为测试预言,为 AWS 的许多测试实践提供正确的答案。正确性测试和形式化方法仍然是 AWS 的关键投资领域,这些领域的投资已经看到了出色的回报,因此加速了投资。
David R. Morrison - 模拟:分布式系统中未充分利用的工具
模拟在人工智能系统的出现中发挥着巨大的作用:我们需要一种高效、快速且经济高效的方式来训练人工智能代理在我们的基础设施中运行,而模拟绝对提供了这种能力。
Matt Fata, Philippe-Joseph Arida, Patrick Hahn, Betsy Beyer - 企业到云端:Google 的虚拟桌面
超过四分之一的 Google 员工使用内部、数据中心托管的虚拟桌面。这种本地产品位于公司网络中,允许用户从世界任何地方远程开发代码、访问内部资源和使用 GUI 工具。在其最显着的特性中,虚拟桌面实例可以根据手头的任务进行调整大小,具有持久的用户存储,并且可以在公司数据中心之间移动以跟随出差的 Google 员工。直到最近,我们的虚拟桌面都托管在使用名为 Ganeti 的自研开源虚拟集群管理系统的 Google 公司网络上的商用硬件上。今天,这项重要且对 Google 至关重要的工作负载在 GCP(Google Compute Platform)上运行。
Pat Helland - 分布式事务之外的生活
本文探讨并命名了一些在拒绝分布式事务的世界中用于实现大规模任务关键型应用程序的实用方法。主题包括管理细粒度的应用程序数据,这些数据可能会随着应用程序的增长而随时间重新分区。设计模式支持在这些可重新分区的数据片段之间发送消息。