Hub documentation
去重
去重
启用 Xet 的仓库使用基于内容定义的分块(CDC)在字节级别(约 64KB 的数据,也称为“块”)进行去重。每个块由一个滚动哈希标识,该哈希根据实际文件内容确定块边界,使其对文件中任何位置的插入或删除都具有鲁棒性。当使用支持 Xet 的客户端将文件上传到基于 Xet 的仓库时,其内容会被拆分为这些可变大小的块。分块后,仅保留 Xet 存储中尚不存在的新块,其余部分均被丢弃。
块级去重也是服务端复制即时完成的原因:
hf buckets cp在仓库和存储桶之间迁移时仅迁移内容哈希,无需重新上传数据。请参阅在仓库和存储桶之间复制文件。
内容定义分块的工作原理
要理解基于内容定义的分块,可以将文件想象成一段长文本。系统使用滚动哈希——一种在字节上滑动的小型数学函数——来扫描数据。每当哈希值命中特定模式时,就会在该位置设置一个分块边界。由于边界由内容本身(而非固定位置)决定,即使周围内容发生变化,相同的数据区域也始终会产生相同的分块。
为什么不用固定大小的块?
考虑在文件中间插入少量数据时会发生什么。在使用固定大小分块的情况下,插入点之后的每个分块边界都会发生偏移,导致所有下游分块失效——尽管大部分数据并未改变:
Original file, fixed 6-byte chunks:
|The qu|ick br|own fo|x jump|s over| the l|azy do|g |
chunk1 chunk2 chunk3 chunk4 chunk5 chunk6 chunk7 chunk8
Insert "very " before "lazy":
|The qu|ick br|own fo|x jump|s over| the v|ery la|zy dog|
chunk1 chunk2 chunk3 chunk4 chunk5 chunk6 chunk7 chunk8
~~~~~~ ~~~~~~ ~~~~~~
3 chunks changed!尽管只插入了 5 个字节,但由于编辑点之后的所有边界都偏移了 5 个位置,8 个块中有 3 个发生了变化。在实际文件中,若块大小为 64KB,一次小规模的编辑就可能导致数百兆字节的块失效。
基于内容定义的块划分保持边界稳定
在使用 CDC 时,边界设置在 content 匹配某个模式的位置——而非固定间隔处。这意味着插入操作只会影响发生编辑的那个块。前后的块保持不变:
Original file, content-defined chunks (boundaries marked by "|"):
|The quick |brown fox |jumps over |the lazy dog|
chunk 1 chunk 2 chunk 3 chunk 4
Insert "very " before "lazy":
|The quick |brown fox |jumps over |the very lazy dog|
chunk 1 chunk 2 chunk 3 chunk 4'
(same) (same) (same) (changed)只有 4 个分块中的 1 个发生了变化——即包含编辑内容的那个分块。其余三个分块逐字节完全相同,因此会被去重。这正是 CDC 对版本化数据如此高效的原因:当更新模型检查点或向数据集追加行时,只需上传并存储发生修改的部分。
从 Chunks 到存储
完整的去重流程如下:
当文件被分块时,每个块的哈希值会与已存储的内容进行比对。这一过程在多个层级进行:首先与当前上传会话中已见过的块进行比对,然后与先前上传元数据的本地缓存进行比对,最后通过全局去重查询,将部分块与 Xet 存储中的所有数据进行比对。重复的块会被完全跳过。新的块会被分组为 64 MB 的块并上传。每个块在内容寻址存储(CAS)中仅存储一次,以其哈希值作为键。
实践中的存储节省
Hub 的当前建议是将文件大小限制在 200 GB。在 64KB 的块大小下,一个 20GB 的文件包含 312,500 个块,其中许多块在不同版本之间保持不变。Git LFS 的设计仅用于检测文件是否已更改,并存储该修订版本的完整内容。通过在块级别进行去重,Xet 后端使得只需存储文件中已修改的内容(可能仅为几 KB 或 MB),并跨仓库安全地去重共享块。对于模型和数据集仓库中常见的大型二进制文件,这显著缩短了文件传输时间。
For more details, refer to the From Files to Chunks and From Chunks to Blocks blog posts, or the Git is for Data paper by Low et al. that served as the launch point for XetHub prior to being acquired by Hugging Face.
Update on GitHub