将 Hub 从 Git LFS 迁移到 Xet
今年 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 的未来。然而,这次迁移的无名英雄是
- 内部称为 Git LFS Bridge 的一个不可或缺的基础设施
- 昼夜不停运行的后台内容迁移
这些组件共同使我们能够在几天内积极迁移 PB 级数据,而无需担心对 Hub 或社区的影响。它们让我们安心地在未来几周和几个月内更快地行动(跳到文章末尾👇查看即将发生的事情)。
桥接和向后兼容性
在规划迁移到 Xet 的早期阶段,我们做了一些关键的设计决策:
- 不会从 Git LFS “硬性切换”到 Xet
- 支持 Xet 的存储库应该能够同时包含 Xet 和 LFS 文件
- 从 LFS 到 Xet 的存储库迁移不需要“锁定”;也就是说,它们可以在后台运行,而不会中断下载或上传
受我们对社区的承诺驱动,这些看似简单的决策产生了重大影响。最重要的是,我们不认为用户和团队必须立即改变他们的工作流程或下载新客户端才能与支持 Xet 的存储库交互。
如果您有支持 Xet 的客户端(例如,hf-xet
,与 huggingface_hub
的 Xet 集成),上传和下载将通过整个 Xet 堆栈。客户端在上传时会 使用内容定义分块将文件分解成块,或者在下载时请求文件重建信息。上传时,块被传递到 CAS 并存储在 S3 中。下载期间,CAS 提供客户端从 S3 请求以在本地重建文件所需的块范围。
对于不支持基于分块的文件传输的旧版本 huggingface_hub
或 huggingface.js,您仍然可以下载和上传到 Xet 存储库,但这些字节将采取不同的路径。当通过 resolve
端点从 Hub 请求 Xet 支持的文件时,Git LFS Bridge 会构建并返回一个单独的 预签名 URL,模仿 LFS 协议。然后,Bridge 完成从 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 内容寻址存储

扩展迁移
四月,我们联系了 bartowski,询问他们是否愿意测试 Xet,从而测试了该系统的极限。bartowski 拥有近 500 TB 的数据,分布在 2,000 个存储库中,其迁移揭示了一些薄弱环节:
- 用于全局重复数据删除的临时分片文件最初写入
/tmp
,然后移动到分片缓存。然而,在我们的 worker pod 上,/tmp
和 Xet 缓存位于不同的挂载点。移动失败,分片文件从未被删除。最终磁盘被填满,触发了一波设备上没有剩余空间
错误。 - 在支持 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 的日常负载。

零摩擦,更快的传输
当我们开始替换 LFS 时,我们有两个目标:
- 不造成损害
- 尽快实现最大影响
根据我们最初的约束和这些目标进行设计,使我们能够:
- 在将
hf-xet
作为必需依赖项包含到huggingface_hub
之前,先引入并强化它 - 支持社区通过他们今天使用的任何方式上传和下载到启用 Xet 的存储库,同时我们的基础设施处理其余部分
- 通过逐步将 Hub 迁移到 Xet,学习宝贵的经验——从规模到我们的客户端在分布式文件系统上的操作方式
我们不必等待所有上传路径都支持 Xet,强制进行硬性切换,或者推动社区采用特定的工作流程,而是可以立即开始将 Hub 迁移到 Xet,对用户影响最小。简而言之,让团队保持他们的工作流程,并与基础设施一起有机地过渡到 Xet,以支持统一存储系统的长期目标。
Xet 面向所有人
在 1 月和 2 月,我们引入了高级用户以提供反馈并进行基础设施压力测试。为了获得社区反馈,我们启动了 一个候补名单,以预览支持 Xet 的存储库。此后不久,Xet 成为 Hub 上新用户的默认设置。
我们现在支持 Hub 上一些最大的创作者(Meta Llama、Google、OpenAI 和 Qwen),同时社区仍可不间断地工作。
下一步?
从本月开始,我们将把 Xet 带给所有人。请留意一封提供 Xet 访问权限的电子邮件,一旦您获得权限,请更新到最新的 huggingface_hub
(pip install -U huggingface_hub
)以立即解锁更快的传输。这也意味着
- 您所有现有的存储库将从 LFS 迁移到 Xet
- 所有新创建的存储库将默认启用 Xet
如果您使用浏览器或 Git 从 Hub 上传或下载,那没关系。基于分块的支持即将推出。在此期间,请使用您已有的任何工作流程;没有任何限制。
接下来:开源 Xet 协议和整个基础设施堆栈。将数据扩展到 AI 工作负载的存储和移动的未来就在 Hub 上,我们的目标是将其带给所有人。