Meta Engineering Blog(RSS)
精选
71AI 编辑部评分,满分 100

Meta 大规模 AI 存储蓝图

2026-07-02 00:00· 45天前
AI 导读

Meta 运营数百 EB 级存储集群,基于 Tectonic 分层存储层构建 BLOB 存储架构,以应对两大挑战:最大化 GPU 利用率与研究迭代速度。传统 BLOB 架构的多层元数据查询可导致数百毫秒延迟,使 GPU 因 I/O 等待停顿。新架构将训练栈逐步迁移到 BLOB 存储接口上,利用闪存提供可预测的低 pMax 延迟,避免单 GPU 慢速拖慢整批任务。同时,统一的数据湖访问支持地理分布 GPU 间的数据高速注入与跨区移动,提升研究效率。

推荐理由

Meta的存储架构复盘给出了一条明确路径,从重写元数据到分层缓存,他们把GPU利用率和研究者迭代速度同时提升了一个档次,做AI训练平台的值得细读。

正文 · AI 翻译

过去几年间,模型能力与训练数据集规模经历了指数级增长。而在最近一年左右,前沿新模型的发布间隔已从数月缩短至数周。可靠且快速的存储访问,对于人工智能创新的速度与计算成本都至关重要。如果说 AI 是大脑,那么存储就是记忆:能力与速度高度依赖于记忆容量与检索速度。

然而,尽管 AI 计算性能大约每两年翻三倍,存储与互连性能的增长却相对平缓。因此,存储瓶颈仍然是导致 AI 工作负载中 GPU 停滞的主要原因之一,直接影响着支出与上市时间。除了 GPU 利用率之外,存储架构还直接影响着 AI 研究的迭代速度;随着 GPU 日益跨地域分布、数据集规模变得极其庞大,研究人员需要花费大量时间跨区域摄取和移动数据,从而影响了研究效率。在这篇博文中,我们将讨论 Meta 的 BLOB 存储架构如何演进,以应对两大核心挑战:最大化 GPU 利用率与最大化研究效率。

存储架构概述

Meta 运营着数百个 EB 级存储集群,为 Meta 所有外部和内部产品提供服务,包括 Facebook、Instagram、Reality Labs、Meta AI、广告、数据仓库和内部数据库。我们的存储服务提供对象存储、文件系统和块设备 API,这些 API 抽象构建在一个名为 Tectonic 的水平可扩展基础块层之上。Tectonic 层是一个区域性的多租户存储架构,利用纠删码技术提供高持久性和高可用性,支持跨介质类型(例如 HDD 和闪存)的分层存储,并管理热数据、冷数据和温数据的智能放置,以实现跨租户的高效 I/O 利用。运行在 Tectonic 之上的 BLOB 存储层则提供了一个全局的、无限可扩展的存储架构,并公开了允许用户在持久性和可用性之间进行权衡的策略。

在之前题为“训练 Llama:存储视角”的 @Scale 演讲中,我们讨论了 Meta 如何通过在其上暴露类似 NFS 的文件系统接口,直接在 Tectonic 块层上训练 Llama。虽然这种架构在 Meta 内部仍被广泛使用,但我们的现代训练栈已开始逐步迁移到 BLOB 存储接口之上,整个行业亦是如此。这一转变的驱动力来自于需要统一访问 BLOB 存储层中的海量数据湖,以及对高性能的需求。

最大化 GPU 利用率

现代 AI 工作负载是“数据饥渴型”的,并且具有与传统 Web 应用截然不同的工作负载特征:突发且持续的高吞吐量、可预测且有界的 pMax 延迟,以及多变的 I/O 模式。近年来,BLOB 存储的重点已大幅转向最大化 GPU 利用率。

延迟为何重要

要理解有界且低 pMax 延迟为何重要,我们不妨以模型训练为例。在训练过程中,数十万块 GPU 会多次(即多个 epoch)迭代处理存储中的海量数据,并以批次为单位训练数据集。每隔一定步数或批次后,GPU 之间会同步彼此的状态。如果某一块 GPU 速度较慢,这一步就会拖慢所有 GPU 以及整个训练过程。

图 1 展示了一个跨两块 GPU 的数据加载流水线。每块 GPU 主机上的数据加载器会预取下一个数据集批次,同时 GPU 正在处理当前批次,以实现计算或 I/O 的最大重叠。在 GPU1 的情况下,存储读取延迟完全在可控范围内,因此 GPU 从未因等待 I/O 而停滞。而在 GPU2 的情况下,有两次存储读取出现了高延迟,导致 GPU 停滞。由于这些停滞,整体步骤完成时间被延迟了。

图 1:跨两块 GPU 的数据加载。

传统 BLOB 存储架构尚未为 AI 做好准备

多年来,BLOB 存储是逐步演化而来的,以真正的面向服务方式层层叠加。其中许多层是有状态的,并维护着各自的元数据存储。虽然这些元数据访问延迟通常不是全球 HDD 所服务的传统用例的瓶颈,但对于需要毫秒级访问闪存数据的 AI 工作负载来说,它们却是拦路虎。图 2 展示了一个典型的 getObject(“/bucket/path”) API 的请求流程。请求到达 API 服务器后,服务器会在 namelayer、volumeslayer 和 containerlayer 之间进行多次元数据查找,然后才能将路径解析为一组 (blockId, offset, size) 元组。其中一些查找可能跨区域,延迟累积到数百毫秒的情况并不少见;只要其中任何一次查找响应缓慢就足以造成问题。查找完成后,API 服务器将数据从 Tectonic 层代理到客户端。

图 2:getObject API 的旧请求流程。

尽管这种架构很好地服务了传统工作负载,但当初决定设计权衡的基本假设如今已经发生了变化。其中一些变化包括:

  • 性能与延迟:如前所述,传统工作负载对延迟的要求相对温和,而 AI 工作负载则要求从低百分位到最高百分位(pMax)全程具备可预测且有界的延迟。
  • 可靠性与持久性:传统架构在设计上具备高持久性和高可用性,即使面对区域级故障也能应对;数据和元数据默认进行全局复制。虽然 AI 工作负载要求极高的可用性,但“默认全局复制”这一设计选择已不再适用。
  • 成本效率:传统技术栈基于 HDD 构建,并针对每字节成本进行了高度优化。AI 工作负载对 IOPS 的需求要求使用闪存,此外,存储的计算成本相对于 GPU 的计算成本而言已变得微不足道。
  • 能效:随着 GPU 的引入,数据中心越来越受限于电力而非空间。每千瓦用于存储的电力,就意味着少了一千瓦用于 GPU 的电力。这是 AI 工作负载带来的新约束。

简而言之,权衡空间已经发生了足够大的变化,促使我们重新思考整个架构。

重建基础

在着手构建新基础时,我们做出了以下主要设计选择:

  • 统一元数据模式:我们重写了元数据子系统,并将分散在不同层的元数据合并为一个由 ZippyDB 支持的统一扁平模式。这为实现 O(1) 复杂度的路径到存储地址的解析铺平了道路,这是一项阶跃性的改进。
  • 无数据平面代理:我们移除了数据平面代理,并构建了一个胖客户端 SDK,能够直接从存储服务器向客户端流式传输字节。这有助于实现能效目标,同时也能实现更高的吞吐量和更低的延迟。
  • 区域部署:BLOB 存储技术栈现在更加精简,可以灵活地作为区域级或全局级服务进行部署。我们现在在每个 AI 区域都部署了一个与 GPU 共置的区域级 BLOB 存储技术栈。
图 3:getObject API 的新请求流程。

图 3 展示了 getObject(“/bucket/path”) 的新请求流程。当客户端上的 SDK 收到此 API 调用时,它会向 API 服务器发出 getReadPlan(“/bucket/path”) 请求。API 服务器对每个数据块执行 O(1) 查找,到新的元数据存储中,将路径映射为 (blockId, offset, size) 元组。然后它将 ReadPlanResult 返回给 SDK。SDK 内部嵌入了 Tectonic BlockClient,因此现在能够直接从 Tectonic 流式读取这些数据块的数据。通过这些改动,我们重建了基础架构,并实现了在 Tectonic 之上零额外开销的目标。通过消除数据代理,我们也保持了功耗预算。

应对流量尖峰与热点

在数据和检查点加载过程中,AI 工作负载通常会跨数百个 GPU 并发访问数据。模型权重等数据子集往往是“热点”,而 GPU 重启等事件会触发剧烈的流量尖峰。在基础架构问题解决后,我们的下一个问题便是应对这些流量尖峰与热点。幸运的是,BLOB 存储层多年来在处理热点方面积累了经验,因此我们在此将现有解决方案适配到了 AI 工作负载上。具体来说,我们采用了两种方法:

  • 分布式数据缓存:我们利用 GPU 主机上的空闲内存作为分布式数据缓存,用于频繁且并发访问的数据。为此,我们复用了 Meta 的 Owl 子系统中的组件:我们将 Owl 子系统中的对等节点直接集成到 BLOB 存储客户端 SDK 中,使得所有数据访问都经过此数据缓存。
  • 读取计划元数据缓存:读取计划指的是从路径到存储地址的映射。我们现在将频繁访问的 BLOB 的读取计划缓存在一个类似于 memcache 的分布式内存存储中。

在实践中,我们观察到分布式数据缓存的平均缓存命中率为 80%,而读取计划缓存提供 1-2 毫秒的元数据访问延迟。本质上,这些简单的机制实现了三件事:

  • 吸收流量尖峰,减少来自存储的 I/O 需求。
  • 解决元数据热点分片问题。
  • 通过从内存提供服务来改善 p50 和 p99 延迟。

协议优化

到目前为止,我们讨论的内容已经解决了 80% 的问题。剩下的 20% 是通过识别并修复整个技术栈中的瓶颈来实现的。以下是一些值得注意的问题,但绝非详尽无遗的清单:

  • 滞后节点:一个缓慢的存储节点导致了尾部延迟。这是一个已被充分理解的问题,我们通过在客户端采用对冲读取来缓解它。
  • 出口流量峰值:在检查点事件期间,客户端常常会产生急剧的出口流量峰值。这反过来又可能导致网络拥塞、超时和重试,最终使 GPU 停滞。我们通过在客户端 SDK 中构建动态并发控制来解决此问题,该控制能根据应用层面的拥塞信号自动调整并行度。

综合以上所有改进,新的 BLOB 存储栈现在能够服务于 AI 工作负载,而不会导致 GPU 停滞,并且在 Tectonic 层之上增加的额外开销微乎其微。我们的下一个重点转向了研究。

最大化研究效率

GPU 资源稀缺且日益呈现地理分布的特点;与此同时,出于性能原因,训练工作负载需要数据与 GPU 位于同一位置。这给研究人员带来了一个有趣的挑战:他们现在需要负责跨区域摄取和迁移数据集。

在 Meta,一次典型的训练任务提交包含以下步骤:

  1. 研究人员从各种来源整理数据,对其进行丰富处理,并将其持久化存储到 BLOB 存储中。
  2. 研究人员选择一个他们想要运行任务的区域。
  3. 研究人员提交一个数据摄取任务,该任务会将训练数据集的快照以针对从 GPU 主机内部加载数据而优化的文件格式,创建到目标区域。
  4. 然后研究人员等待摄取完成;根据数据集的大小,这可能需要数小时。
  5. 研究人员提交他们的训练任务并监控运行情况。
  6. 研究人员分析输出结果,调整数据集,然后从第 3 步开始再次迭代。

步骤 2 到 4 可能需要数小时,直接影响研究人员的迭代速度。理想情况下,我们希望研究人员把时间花在调优模型上,而不是等待存储。目前,研究人员在启动任务前会复制数据快照,以便将数据与 GPU 放在同一位置,从而获得最佳性能。虽然这种性能优化对于持续数周或数月的大规模训练任务来说是有意义的,但绝大多数任务规模要小得多;负责这些任务的研究人员更愿意用偶尔的性能下降来换取迭代速度。

因此,我们需要一个系统,让研究人员能够一次性摄入数据,并在任何地方访问数据,无需考虑区域边界。我们需要一种工作流,让研究人员能在几分钟内完成迭代,而不是几小时。当我们重新回到设计阶段时,这些数据集“一次写入、多次读取”的特性让我们灵光一现。如果我们把存储看作一台行星级计算机中的磁盘,并从操作系统世界借鉴一些想法,会怎么样?当运行在 CPU 核心上的 Linux 进程尝试从磁盘读取文件时,操作系统会透明地按需将数据填充到缓存的各个层级——内存中的页缓存以及 L2 和 L1 CPU 缓存。这一直觉引出了图 4 中的架构演进:

图 4:数据加载架构演进。

核心思想是利用各种主机内和主机外的存储资源作为分层缓存,并以基于 HDD 的全局 BLOB 存储架构作为最终数据源。具体来说,我们利用 GPU 主机上的内存和闪存作为 L1 和 L2 缓存。同时,我们利用基于闪存的区域 BLOB 存储架构作为 L3 缓存,数据加载器继续通过熟悉的 BLOB 存储 SDK 访问存储。为了有效隐藏延迟并简化数据生命周期,我们依赖以下机制:

  • 数据加载器预取:数据加载器在处理当前批次数据的同时,将下一批数据集预取到内存中。这种预取在 BLOB 存储 SDK 层面会表现为一次读取操作。
  • 深度预取:我们在 BLOB 存储 SDK 中公开了一个显式的 `prefetch()` API。数据加载器会在后台调用 `prefetch()` API,触发对未来几分钟内所需数据的显式预取。该 API 会触发数据从远程存储水化到本地区域 L3 缓存,同时预热元数据缓存。
  • 自动数据生命周期:L3 区域分离式闪存层中的数据通常会保留一段配置好的时间,以便在训练周期内跨轮次复用。我们支持自定义驱逐策略,包括 TTL 和 LRU 策略。这些驱逐策略也具备容量/配额感知能力。

这种新的数据加载范式一经投入生产部署,便迅速得到广泛采用,目前我们在生产环境中同时支持这两种数据加载范式。为了用数据说明其影响,图 5 展示了所有工作负载在部署前后的数据摄入时间对比:

图 5:部署前后的数据摄入时间。

在如今前沿模型每隔数周就会发布的世界里,这种数据加载范式的转变正是为了进一步加速所亟需的变革。

关键要点

现代 AI 工作负载对数据的需求极大,存储对计算成本和创新速度都起着重要作用。存储瓶颈直接影响 GPU 利用率和计算成本,而在 GPU 跨地域分布的情况下,跨区域数据摄入所花费的时间直接影响研究迭代的速度。Meta 的 BLOB 存储架构最初是为服务 Meta 旗下应用家族而构建的,我们需要在性能上实现阶跃式提升才能满足 AI 工作负载的需求。这促使我们重新思考整个架构。通过重建元数据子系统,并采用带有预取/按需水化功能的分层缓存架构,我们能够有效满足当前工作负载的需求。

未来工作

我们持续演进 Meta 的存储系统,以跟上硬件演进和工作负载需求的变化。该领域的一些未来工作将包括:

  • 将存储扩展到网络极限。
  • 在更高规模下支持检查点操作而不阻塞 GPU。
  • 推理工作负载面临的新挑战,我们已开始着手应对。

来源:Meta Engineering Blog(RSS) · engineering.fb.com

Meta 大规模 AI 存储蓝图

Meta Engineering Blog(RSS)·2026-07-02 00:00·45天前
AI 导读

Meta 运营数百 EB 级存储集群,基于 Tectonic 分层存储层构建 BLOB 存储架构,以应对两大挑战:最大化 GPU 利用率与研究迭代速度。传统 BLOB 架构的多层元数据查询可导致数百毫秒延迟,使 GPU 因 I/O 等待停顿。新架构将训练栈逐步迁移到 BLOB 存储接口上,利用闪存提供可预测的低 pMax 延迟,避免单 GPU 慢速拖慢整批任务。同时,统一的数据湖访问支持地理分布 GPU 间的数据高速注入与跨区移动,提升研究效率。

正文 · AI 翻译

过去几年间,模型能力与训练数据集规模经历了指数级增长。而在最近一年左右,前沿新模型的发布间隔已从数月缩短至数周。可靠且快速的存储访问,对于人工智能创新的速度与计算成本都至关重要。如果说 AI 是大脑,那么存储就是记忆:能力与速度高度依赖于记忆容量与检索速度。

然而,尽管 AI 计算性能大约每两年翻三倍,存储与互连性能的增长却相对平缓。因此,存储瓶颈仍然是导致 AI 工作负载中 GPU 停滞的主要原因之一,直接影响着支出与上市时间。除了 GPU 利用率之外,存储架构还直接影响着 AI 研究的迭代速度;随着 GPU 日益跨地域分布、数据集规模变得极其庞大,研究人员需要花费大量时间跨区域摄取和移动数据,从而影响了研究效率。在这篇博文中,我们将讨论 Meta 的 BLOB 存储架构如何演进,以应对两大核心挑战:最大化 GPU 利用率与最大化研究效率。

存储架构概述

Meta 运营着数百个 EB 级存储集群,为 Meta 所有外部和内部产品提供服务,包括 Facebook、Instagram、Reality Labs、Meta AI、广告、数据仓库和内部数据库。我们的存储服务提供对象存储、文件系统和块设备 API,这些 API 抽象构建在一个名为 Tectonic 的水平可扩展基础块层之上。Tectonic 层是一个区域性的多租户存储架构,利用纠删码技术提供高持久性和高可用性,支持跨介质类型(例如 HDD 和闪存)的分层存储,并管理热数据、冷数据和温数据的智能放置,以实现跨租户的高效 I/O 利用。运行在 Tectonic 之上的 BLOB 存储层则提供了一个全局的、无限可扩展的存储架构,并公开了允许用户在持久性和可用性之间进行权衡的策略。

在之前题为“训练 Llama:存储视角”的 @Scale 演讲中,我们讨论了 Meta 如何通过在其上暴露类似 NFS 的文件系统接口,直接在 Tectonic 块层上训练 Llama。虽然这种架构在 Meta 内部仍被广泛使用,但我们的现代训练栈已开始逐步迁移到 BLOB 存储接口之上,整个行业亦是如此。这一转变的驱动力来自于需要统一访问 BLOB 存储层中的海量数据湖,以及对高性能的需求。

最大化 GPU 利用率

现代 AI 工作负载是“数据饥渴型”的,并且具有与传统 Web 应用截然不同的工作负载特征:突发且持续的高吞吐量、可预测且有界的 pMax 延迟,以及多变的 I/O 模式。近年来,BLOB 存储的重点已大幅转向最大化 GPU 利用率。

延迟为何重要

要理解有界且低 pMax 延迟为何重要,我们不妨以模型训练为例。在训练过程中,数十万块 GPU 会多次(即多个 epoch)迭代处理存储中的海量数据,并以批次为单位训练数据集。每隔一定步数或批次后,GPU 之间会同步彼此的状态。如果某一块 GPU 速度较慢,这一步就会拖慢所有 GPU 以及整个训练过程。

图 1 展示了一个跨两块 GPU 的数据加载流水线。每块 GPU 主机上的数据加载器会预取下一个数据集批次,同时 GPU 正在处理当前批次,以实现计算或 I/O 的最大重叠。在 GPU1 的情况下,存储读取延迟完全在可控范围内,因此 GPU 从未因等待 I/O 而停滞。而在 GPU2 的情况下,有两次存储读取出现了高延迟,导致 GPU 停滞。由于这些停滞,整体步骤完成时间被延迟了。

图 1:跨两块 GPU 的数据加载。

传统 BLOB 存储架构尚未为 AI 做好准备

多年来,BLOB 存储是逐步演化而来的,以真正的面向服务方式层层叠加。其中许多层是有状态的,并维护着各自的元数据存储。虽然这些元数据访问延迟通常不是全球 HDD 所服务的传统用例的瓶颈,但对于需要毫秒级访问闪存数据的 AI 工作负载来说,它们却是拦路虎。图 2 展示了一个典型的 getObject(“/bucket/path”) API 的请求流程。请求到达 API 服务器后,服务器会在 namelayer、volumeslayer 和 containerlayer 之间进行多次元数据查找,然后才能将路径解析为一组 (blockId, offset, size) 元组。其中一些查找可能跨区域,延迟累积到数百毫秒的情况并不少见;只要其中任何一次查找响应缓慢就足以造成问题。查找完成后,API 服务器将数据从 Tectonic 层代理到客户端。

图 2:getObject API 的旧请求流程。

尽管这种架构很好地服务了传统工作负载,但当初决定设计权衡的基本假设如今已经发生了变化。其中一些变化包括:

  • 性能与延迟:如前所述,传统工作负载对延迟的要求相对温和,而 AI 工作负载则要求从低百分位到最高百分位(pMax)全程具备可预测且有界的延迟。
  • 可靠性与持久性:传统架构在设计上具备高持久性和高可用性,即使面对区域级故障也能应对;数据和元数据默认进行全局复制。虽然 AI 工作负载要求极高的可用性,但“默认全局复制”这一设计选择已不再适用。
  • 成本效率:传统技术栈基于 HDD 构建,并针对每字节成本进行了高度优化。AI 工作负载对 IOPS 的需求要求使用闪存,此外,存储的计算成本相对于 GPU 的计算成本而言已变得微不足道。
  • 能效:随着 GPU 的引入,数据中心越来越受限于电力而非空间。每千瓦用于存储的电力,就意味着少了一千瓦用于 GPU 的电力。这是 AI 工作负载带来的新约束。

简而言之,权衡空间已经发生了足够大的变化,促使我们重新思考整个架构。

重建基础

在着手构建新基础时,我们做出了以下主要设计选择:

  • 统一元数据模式:我们重写了元数据子系统,并将分散在不同层的元数据合并为一个由 ZippyDB 支持的统一扁平模式。这为实现 O(1) 复杂度的路径到存储地址的解析铺平了道路,这是一项阶跃性的改进。
  • 无数据平面代理:我们移除了数据平面代理,并构建了一个胖客户端 SDK,能够直接从存储服务器向客户端流式传输字节。这有助于实现能效目标,同时也能实现更高的吞吐量和更低的延迟。
  • 区域部署:BLOB 存储技术栈现在更加精简,可以灵活地作为区域级或全局级服务进行部署。我们现在在每个 AI 区域都部署了一个与 GPU 共置的区域级 BLOB 存储技术栈。
图 3:getObject API 的新请求流程。

图 3 展示了 getObject(“/bucket/path”) 的新请求流程。当客户端上的 SDK 收到此 API 调用时,它会向 API 服务器发出 getReadPlan(“/bucket/path”) 请求。API 服务器对每个数据块执行 O(1) 查找,到新的元数据存储中,将路径映射为 (blockId, offset, size) 元组。然后它将 ReadPlanResult 返回给 SDK。SDK 内部嵌入了 Tectonic BlockClient,因此现在能够直接从 Tectonic 流式读取这些数据块的数据。通过这些改动,我们重建了基础架构,并实现了在 Tectonic 之上零额外开销的目标。通过消除数据代理,我们也保持了功耗预算。

应对流量尖峰与热点

在数据和检查点加载过程中,AI 工作负载通常会跨数百个 GPU 并发访问数据。模型权重等数据子集往往是“热点”,而 GPU 重启等事件会触发剧烈的流量尖峰。在基础架构问题解决后,我们的下一个问题便是应对这些流量尖峰与热点。幸运的是,BLOB 存储层多年来在处理热点方面积累了经验,因此我们在此将现有解决方案适配到了 AI 工作负载上。具体来说,我们采用了两种方法:

  • 分布式数据缓存:我们利用 GPU 主机上的空闲内存作为分布式数据缓存,用于频繁且并发访问的数据。为此,我们复用了 Meta 的 Owl 子系统中的组件:我们将 Owl 子系统中的对等节点直接集成到 BLOB 存储客户端 SDK 中,使得所有数据访问都经过此数据缓存。
  • 读取计划元数据缓存:读取计划指的是从路径到存储地址的映射。我们现在将频繁访问的 BLOB 的读取计划缓存在一个类似于 memcache 的分布式内存存储中。

在实践中,我们观察到分布式数据缓存的平均缓存命中率为 80%,而读取计划缓存提供 1-2 毫秒的元数据访问延迟。本质上,这些简单的机制实现了三件事:

  • 吸收流量尖峰,减少来自存储的 I/O 需求。
  • 解决元数据热点分片问题。
  • 通过从内存提供服务来改善 p50 和 p99 延迟。

协议优化

到目前为止,我们讨论的内容已经解决了 80% 的问题。剩下的 20% 是通过识别并修复整个技术栈中的瓶颈来实现的。以下是一些值得注意的问题,但绝非详尽无遗的清单:

  • 滞后节点:一个缓慢的存储节点导致了尾部延迟。这是一个已被充分理解的问题,我们通过在客户端采用对冲读取来缓解它。
  • 出口流量峰值:在检查点事件期间,客户端常常会产生急剧的出口流量峰值。这反过来又可能导致网络拥塞、超时和重试,最终使 GPU 停滞。我们通过在客户端 SDK 中构建动态并发控制来解决此问题,该控制能根据应用层面的拥塞信号自动调整并行度。

综合以上所有改进,新的 BLOB 存储栈现在能够服务于 AI 工作负载,而不会导致 GPU 停滞,并且在 Tectonic 层之上增加的额外开销微乎其微。我们的下一个重点转向了研究。

最大化研究效率

GPU 资源稀缺且日益呈现地理分布的特点;与此同时,出于性能原因,训练工作负载需要数据与 GPU 位于同一位置。这给研究人员带来了一个有趣的挑战:他们现在需要负责跨区域摄取和迁移数据集。

在 Meta,一次典型的训练任务提交包含以下步骤:

  1. 研究人员从各种来源整理数据,对其进行丰富处理,并将其持久化存储到 BLOB 存储中。
  2. 研究人员选择一个他们想要运行任务的区域。
  3. 研究人员提交一个数据摄取任务,该任务会将训练数据集的快照以针对从 GPU 主机内部加载数据而优化的文件格式,创建到目标区域。
  4. 然后研究人员等待摄取完成;根据数据集的大小,这可能需要数小时。
  5. 研究人员提交他们的训练任务并监控运行情况。
  6. 研究人员分析输出结果,调整数据集,然后从第 3 步开始再次迭代。

步骤 2 到 4 可能需要数小时,直接影响研究人员的迭代速度。理想情况下,我们希望研究人员把时间花在调优模型上,而不是等待存储。目前,研究人员在启动任务前会复制数据快照,以便将数据与 GPU 放在同一位置,从而获得最佳性能。虽然这种性能优化对于持续数周或数月的大规模训练任务来说是有意义的,但绝大多数任务规模要小得多;负责这些任务的研究人员更愿意用偶尔的性能下降来换取迭代速度。

因此,我们需要一个系统,让研究人员能够一次性摄入数据,并在任何地方访问数据,无需考虑区域边界。我们需要一种工作流,让研究人员能在几分钟内完成迭代,而不是几小时。当我们重新回到设计阶段时,这些数据集“一次写入、多次读取”的特性让我们灵光一现。如果我们把存储看作一台行星级计算机中的磁盘,并从操作系统世界借鉴一些想法,会怎么样?当运行在 CPU 核心上的 Linux 进程尝试从磁盘读取文件时,操作系统会透明地按需将数据填充到缓存的各个层级——内存中的页缓存以及 L2 和 L1 CPU 缓存。这一直觉引出了图 4 中的架构演进:

图 4:数据加载架构演进。

核心思想是利用各种主机内和主机外的存储资源作为分层缓存,并以基于 HDD 的全局 BLOB 存储架构作为最终数据源。具体来说,我们利用 GPU 主机上的内存和闪存作为 L1 和 L2 缓存。同时,我们利用基于闪存的区域 BLOB 存储架构作为 L3 缓存,数据加载器继续通过熟悉的 BLOB 存储 SDK 访问存储。为了有效隐藏延迟并简化数据生命周期,我们依赖以下机制:

  • 数据加载器预取:数据加载器在处理当前批次数据的同时,将下一批数据集预取到内存中。这种预取在 BLOB 存储 SDK 层面会表现为一次读取操作。
  • 深度预取:我们在 BLOB 存储 SDK 中公开了一个显式的 `prefetch()` API。数据加载器会在后台调用 `prefetch()` API,触发对未来几分钟内所需数据的显式预取。该 API 会触发数据从远程存储水化到本地区域 L3 缓存,同时预热元数据缓存。
  • 自动数据生命周期:L3 区域分离式闪存层中的数据通常会保留一段配置好的时间,以便在训练周期内跨轮次复用。我们支持自定义驱逐策略,包括 TTL 和 LRU 策略。这些驱逐策略也具备容量/配额感知能力。

这种新的数据加载范式一经投入生产部署,便迅速得到广泛采用,目前我们在生产环境中同时支持这两种数据加载范式。为了用数据说明其影响,图 5 展示了所有工作负载在部署前后的数据摄入时间对比:

图 5:部署前后的数据摄入时间。

在如今前沿模型每隔数周就会发布的世界里,这种数据加载范式的转变正是为了进一步加速所亟需的变革。

关键要点

现代 AI 工作负载对数据的需求极大,存储对计算成本和创新速度都起着重要作用。存储瓶颈直接影响 GPU 利用率和计算成本,而在 GPU 跨地域分布的情况下,跨区域数据摄入所花费的时间直接影响研究迭代的速度。Meta 的 BLOB 存储架构最初是为服务 Meta 旗下应用家族而构建的,我们需要在性能上实现阶跃式提升才能满足 AI 工作负载的需求。这促使我们重新思考整个架构。通过重建元数据子系统,并采用带有预取/按需水化功能的分层缓存架构,我们能够有效满足当前工作负载的需求。

未来工作

我们持续演进 Meta 的存储系统,以跟上硬件演进和工作负载需求的变化。该领域的一些未来工作将包括:

  • 将存储扩展到网络极限。
  • 在更高规模下支持检查点操作而不阻塞 GPU。
  • 推理工作负载面临的新挑战,我们已开始着手应对。

来源:Meta Engineering Blog(RSS)· engineering.fb.com