将 Hub 从 Git LFS 迁移到 Xet

发布于 2025 年 7 月 15 日
在 GitHub 上更新

今年 1 月,Hugging Face 的 Xet 团队部署了一个新的存储后端,此后不久便将 约 6% 的 Hub 下载流量转移到了该基础设施。这代表着一个重要的里程碑,但这仅仅是个开始。在 6 个月内,50 万个存储 20 PB 数据的存储库加入了 Xet 迁移,因为 Hub 已经超越了 Git LFS,并正在向一个能够随 AI 构建者工作负载扩展的存储系统过渡。

如今,Hub 上有超过 100 万人正在使用 Xet。5 月,它成为 Hub 上新用户和组织默认的存储系统。仅有几十个 GitHub 问题、论坛帖子和 Discord 消息,这可能是如此规模迁移中最安静的一次。

如何做到?首先,团队凭借多年构建和支持内容寻址存储 (CAS) 和 Rust 客户端的经验做好了准备,这些构成了系统基础。如果没有这些部分,Git LFS 可能仍然是 Hub 的未来。然而,这次迁移的无名英雄是

  1. 内部称为 Git LFS Bridge 的一个不可或缺的基础设施
  2. 昼夜不停运行的后台内容迁移

这些组件共同使我们能够在几天内积极迁移 PB 级数据,而无需担心对 Hub 或社区的影响。它们让我们安心地在未来几周和几个月内更快地行动(跳到文章末尾👇查看即将发生的事情)。

桥接和向后兼容性

在规划迁移到 Xet 的早期阶段,我们做了一些关键的设计决策:

  • 不会从 Git LFS “硬性切换”到 Xet
  • 支持 Xet 的存储库应该能够同时包含 Xet 和 LFS 文件
  • 从 LFS 到 Xet 的存储库迁移不需要“锁定”;也就是说,它们可以在后台运行,而不会中断下载或上传

受我们对社区的承诺驱动,这些看似简单的决策产生了重大影响。最重要的是,我们不认为用户和团队必须立即改变他们的工作流程或下载新客户端才能与支持 Xet 的存储库交互。

如果您有支持 Xet 的客户端(例如,hf-xet,与 huggingface_hub 的 Xet 集成),上传和下载将通过整个 Xet 堆栈。客户端在上传时会 使用内容定义分块将文件分解成块,或者在下载时请求文件重建信息。上传时,块被传递到 CAS 并存储在 S3 中。下载期间,CAS 提供客户端从 S3 请求以在本地重建文件所需的块范围

对于不支持基于分块的文件传输的旧版本 huggingface_hubhuggingface.js,您仍然可以下载和上传到 Xet 存储库,但这些字节将采取不同的路径。当通过 resolve 端点从 Hub 请求 Xet 支持的文件时,Git LFS Bridge 会构建并返回一个单独的 预签名 URL,模仿 LFS 协议。然后,Bridge 完成从 S3 中保存的内容重建文件并将其返回给请求者的工作。

Git LFS Bridge flow
Git LFS Bridge 的极大简化视图——实际上,此路径包括更多的 API 调用和组件,例如位于 Bridge 前端的 CDN、用于文件元数据的 DynamoDB 以及 S3 本身。

要查看实际效果,请右键单击上图并在新选项卡中打开它。URL 从 https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/migrating-the-hub-to-xet/bridge.png 重定向到以 https://cas-bridge.xethub.hf.co/xet-bridge-us/... 开头的 URL。您也可以在终端中使用 curl -vL 对同一 URL 查看重定向。

同时,当非 Xet 感知客户端上传文件时,文件首先发送到 LFS 存储,然后迁移到 Xet。这个“后台迁移过程”在我们文档中简要提及,它支持向 Xet 的迁移以及上传向后兼容性。它是数十 PB 模型和数据集迁移的幕后推手,并使 500,000 个存储库与 Xet 存储保持同步,所有这些都没有中断。

每次需要将文件从 LFS 迁移到 Xet 时,都会触发一个 webhook,将事件推送到分布式队列,由协调器处理。协调器

  • 如果事件要求,则在存储库上启用 Xet
  • 获取存储库中每个 LFS 文件的 LFS 版本列表
  • 根据文件大小或文件数量将文件分批处理为作业;以 1000 个文件或 500MB 为准,以先达到者为准
  • 将作业放置在另一个队列中,供迁移工作进程 pod 处理

然后,这些迁移工作进程获取作业,每个 pod

  • 下载批处理中列出的 LFS 文件
  • 使用 xet-core 将 LFS 文件上传到 Xet 内容寻址存储
Migration flow
由 webhook 事件触发的迁移流程;为简洁起见,从协调器开始。

扩展迁移

四月,我们联系了 bartowski,询问他们是否愿意测试 Xet,从而测试了该系统的极限。bartowski 拥有近 500 TB 的数据,分布在 2,000 个存储库中,其迁移揭示了一些薄弱环节:

  • 用于全局重复数据删除的临时分片文件最初写入 /tmp,然后移动到分片缓存。然而,在我们的 worker pod 上,/tmpXet 缓存位于不同的挂载点。移动失败,分片文件从未被删除。最终磁盘被填满,触发了一波 设备上没有剩余空间 错误。
  • 在支持 Llama 4 发布后,我们为突发下载扩展了 CAS,但迁移工作进程却颠倒了局面,数百个多 GB 的上传将 CAS 推到了其资源极限之外。
  • 从理论上讲,迁移工作进程能够实现比报告的吞吐量高得多的吞吐量;对 pod 进行性能分析揭示了网络和 EBS I/O 瓶颈。

解决这个三头怪物意味着触及每一个层面——修补 xet-core、调整 CAS 大小以及增强工作节点规格。幸运的是,bartowski 愿意与我们合作,直到每个存储库都迁移到 Xet。这些经验教训也为 Hub 上最大的存储用户(如 RichardErkhov(1.7PB 和 25,000 个存储库)和 mradermacher(6.1PB 和 42,000 个存储库 🤯))的迁移提供了动力。

与此同时,CAS 的吞吐量在第一次和最近一次大规模迁移之间增长了一个数量级

  • Bartowski 迁移:CAS 持续约 35 Gb/s,其中约 5 Gb/s 来自常规 Hub 流量。
  • mradermacher 和 RichardErkhov 迁移:CAS 峰值约为 300 Gb/s,同时仍服务于约 40 Gb/s 的日常负载。
Cas throughput
CAS 吞吐量;每个尖峰对应一次重要的迁移,基线吞吐量稳步增加,截至 2025 年 7 月略低于 100 Gb/s

零摩擦,更快的传输

当我们开始替换 LFS 时,我们有两个目标:

  1. 不造成损害
  2. 尽快实现最大影响

根据我们最初的约束和这些目标进行设计,使我们能够:

  • 在将 hf-xet 作为必需依赖项包含到 huggingface_hub 之前,先引入并强化它
  • 支持社区通过他们今天使用的任何方式上传和下载到启用 Xet 的存储库,同时我们的基础设施处理其余部分
  • 通过逐步将 Hub 迁移到 Xet,学习宝贵的经验——从规模到我们的客户端在分布式文件系统上的操作方式

我们不必等待所有上传路径都支持 Xet,强制进行硬性切换,或者推动社区采用特定的工作流程,而是可以立即开始将 Hub 迁移到 Xet,对用户影响最小。简而言之,让团队保持他们的工作流程,并与基础设施一起有机地过渡到 Xet,以支持统一存储系统的长期目标。

Xet 面向所有人

在 1 月和 2 月,我们引入了高级用户以提供反馈并进行基础设施压力测试。为了获得社区反馈,我们启动了 一个候补名单,以预览支持 Xet 的存储库。此后不久,Xet 成为 Hub 上新用户的默认设置。

我们现在支持 Hub 上一些最大的创作者(Meta LlamaGoogleOpenAIQwen),同时社区仍可不间断地工作。

下一步?

从本月开始,我们将把 Xet 带给所有人。请留意一封提供 Xet 访问权限的电子邮件,一旦您获得权限,请更新到最新的 huggingface_hubpip install -U huggingface_hub)以立即解锁更快的传输。这也意味着

  • 您所有现有的存储库将从 LFS 迁移到 Xet
  • 所有新创建的存储库将默认启用 Xet

如果您使用浏览器或 Git 从 Hub 上传或下载,那没关系。基于分块的支持即将推出。在此期间,请使用您已有的任何工作流程;没有任何限制。

接下来:开源 Xet 协议和整个基础设施堆栈。将数据扩展到 AI 工作负载的存储和移动的未来就在 Hub 上,我们的目标是将其带给所有人。

如果您有任何问题,请在评论中给我们留言 👇,在 Xet 团队 页面上 开启讨论

社区

也许是个愚蠢的问题:Xet 不仅应该能提升速度,还应该提供显著的存储优势,即只需上传/存储给定对象的差异,对吗?

我问这个是因为我的账户已迁移到 Xet,但我没有看到迁移后创建的任何存储配额有任何减少。例如,据我所知,如果我创建一个 1 GB 的数据集仓库,更改几行并重新推送,存储使用量会显示 2+ GB。我是不是错过了什么?

文章作者

一点也不愚蠢。Hub 根据每个新对象的逻辑大小报告存储空间;您所看到的是预期的。

我们这样做是为了确保

  • 可预测性——存储库存储始终是文件和版本的总和;您无需考虑存储引擎在幕后如何运行
  • 公平性/一致性——去重是全局的;因此,没有透明的方法来确定内容的拥有权,如果有人从他们的存储库中删除了这些字节,也没有公平的方法重新分配共享内容的拥有权

对于您描述的使用场景,Xet 仍然提供更快的传输速度,因为需要推送和拉取的数据更少,所以更改完成得更快,并且使用更少的带宽/计算资源。

这使得并加强了我们向开源社区提供免费公共存储的承诺。当然,我们一直在评估如何透明地呈现这一点并支持社区,所以如果这其中有任何令人困惑的地方,请告诉我。

·

明白了,没想到是全局去重,这说得通(顺便问一下,去重是在上传之后完成的,还是 Xet 在上传之前会某种程度上与 20+ PB 的数据进行差异比较?)。

我目前还没受到这个问题的影响(谢天谢地 🙏),也不是我能决定的,但如果私有存储也以同样的方式处理,就会有一些有趣的……影响。例如,如果用户为额外的私有存储付费,而他们的存储按“完整大小”计入限制,但实际上却与 Hub 的其余部分进行了去重,因此实际大小只占一小部分,这公平吗?等等。

注册登录 发表评论