3fs learning

Ethereal Lv4

1. 设计

1.1 架构

1.1.1 客户端

  • fuse(需要多次内核态和用户态拷贝,多线程锁抢占性能不佳)

  • Native client(USRBIO)

    • File metadata 仍然走fuse daemon流程(例如open/close/stat)。

    • 数据通路走native client:自己开发的library动态库

    • 每个 USRBIO 实例使用一个 Iov 文件和一个 Ior 文件

      • Iov 文件用来作为读写数据的 buffer
        • 用户提前规划好需要使用的总容量
        • 文件创建之后 FUSE Daemon 将该其注册成 RDMA memory buffer,进而实现整个链路的零拷贝
      • Ior 文件用来实现 IoRing
        • 用户提前规划好并发度
        • 在整个文件上抽象出了提交队列和完成队列,具体布局参考上图
        • 文件的尾部是提交完成队列的信号量,FUSE Daemon 在处理完 IO 后通过这个信号量通知到用户进程
    • 一个挂载点的所有 USRBIO 共享 3 个 submit sem 文件

      • 这三个文件作为 IO 提交事件的信号量(submit sem),每一个文件代表一个优先级

      • 一旦某个 USRBIO 实例有 IO 需要提交,会通过该信号量通知到 FUSE Daemon

    • 所有的共享内存文件在挂载点 3fs-virt/iovs/ 目录下均建有 symlink,指向 /dev/shm 下的对应文件。

    picture.image

1.1.2 服务端

  • cluster manager:集群状态管理,使用例如etcd等保证,实际使用FoundationDB

  • meta service:使用FoundationDB存储元数据。

  • storage service:利用Chain Replication with Apportioned Queries保证一致性。

v2-fe5d3f294916ce8b6d95f630208702c6_1440w

picture.image

1.2 无缓存(针对大模型场景随机读设计,缓存失效)

在存储系统发展的早期,DRAM 缓存加 HDD 是主流方案,缓存设计弥补了硬件性能的巨大差距。随着 SSD 的引入,DRAM+SSD 的组合成为优化热点数据的利器。然而,全闪存时代的到来让复杂的缓存机制逐渐成为瓶颈。NVMe SSD 的超高性能,使得 DRAM 缓存在某些场景下反而拖慢了系统效率。

1.3 链式(CRAQ )

1.3.1 具体操作流程

CARQ标准实现写操作流程:

  1. 客户端把请求发给chain中的head target.
  2. head target本地执行完写请求后,把请求转发给 second target, second target同样先完成本地写操作后转发tail target.
  3. tail target 写成功后,会返回ack给前一个target,同样的ack最后返回给head target.
  4. head target返回给client,应答客户端成功。

3FS的的具体写操作

  1. storage  service接收到write request后,需要检查request带的chain的版本是否是本地最新的版本。如果不是,拒绝该write请求。
  2. 写操作:target service数据通过RDMA Read操作实现,也就说是通过pull的方式拉取的。
  3. 不支持对同一个chunk的并发操作。在head target实现对同一个chunk的并发操作的串行访问:当数据写入到target的memory buffer中时,会对该chunk加lock锁住。
  4. 每个storage service节点上可能存在同一个chunk的两个版本:committed version和 pending version. 版本号都是单调增加的:pending version = committed version + 1
  5. 在tail target,如果写操作成功,更新commited version为最新的pending version,并返回给前一个(predecessor) target
  6. 当每个target收到后面(successor)target的成功的ack返回消息,committed version就会变为最新的pending version,并把ack信息继续返回给predecessor target,本地的chunk lock会被释放。
  7. head target会做同样的操作:修改commited version,释放chunk lock,返回客户端写操作成功的ack消息。

3FS读操作

3FS的读操作可以发送给任意一个chunk副本:

  1. 当storage service收到读请求,检查如果对应的data chunk只有一个committed version,就把该版本的数据直接返回给client

    1. NodeX 检查本地 commitVer 和 updateVer 是否相等;

      • 步骤 2.1:如果不等,说明有其它 flying 的写请求,通知 Client 重试;
      • 步骤 2.2:如果相等,则从本地 chunk 读取数据,并通过 RDMA 写给 Client;
  2. 和原始的CRAQ不同,3FS的实现并没有去tail target上去查询确认版本信息。而是提供了两个选项:

    1. 直接返回给客户端一个special status code,用户等一段时间后去重试。

    2. 客户端对数据一致性要求不敏感,可以直接返回pending version版本的数据给客户端。

错误处理

如果chain中的target故障,就把该target从chain中删除,然后请求重试。

3FS系统中的具体处理方法是把故障的target添加到chain链的末尾并标记为offline状态。

1.3.2 优化

  • 写操作顺序确认(Write-All):虽然写操作需沿链顺序传播到所有节点,但RDMA的特性显著优化了这一过程:

    • RDMA的单边操作(One-Sided):节点间通过RDMA直接写入下一节点的内存,无需目标节点CPU介入,降低写延迟。

    • 流水线化传输:链中节点可并行处理RDMA写入请求,利用高带宽网络实现高效流水线,减少整体写时延。

  • 读操作完全卸载:由于读请求由任意节点直接通过RDMA响应,主机的CPU无需处理网络协议栈,释放计算资源用于其他任务(如元数据管理或写协调)。

  • 批量处理与高效同步:RDMA支持大规模并发数据传输,CRAQ的版本控制机制(如元数据一致性标记)可快速同步,避免传统网络协议中的ACK风暴。
    v2-0edac3d23a41091586120e2a134a0085_r

1.3 小文件以及布局

  • FFRecord

picture.image

  • 布局
    picture.image

1.4 数据恢复

存储服务崩溃、重启、介质故障,对应的存储 Target 不参与数据写操作,会被移动到 chain 的末尾。

  1. 数据恢复流程
  • 步骤 1:Local Node 向 Remote Node 发起 meta 获取,Remote Node 读取本地 meta;
  • 步骤 2:Remote Node 向 Local Node 返回元数据信息,Local Node 比对数据差异;
  • 步骤 3:若数据有差异,Local Node 读取本地 chunk 数据到内存;
  • 步骤 4:Remote Node 单边读取 Local Node chunk 内存数据;
  • 步骤 5:Remote Node 申请新 chunk,并把数据写入新 chunk。
  1. Sync Data 原则:
  • 如果 chunk Local Node 存在 Remote Node 不存在,需要同步;
  • 如果 Remote Node 存在 Local Node不存在,需要删除;
  • 如果 Local Node 的 chain version 大于Remote Node,需要同步;
  • 如果 Local Node 和Remote Node chain version 一样大,但是 commit version 不同,需要同步;
  • 其他情况,包括完全相同的数据,或者正在写入的请求数据,不需要同步。

1.5 3FS 如何优化 KV Cache?

  1. 存储容量扩展性(分离式架构核心价值)

    • 通过存储计算分离,3FS 可将 KV Cache 存储在专用存储节点池而非 GPU 显存/DRAM 中

    • 单节点可支持 TB 级缓存容量(DRAM 方案通常<1TB),允许部署千亿参数模型

    • 典型案例:单个 A100 GPU 显存仅 80GB,而 3FS 集群可线性扩展至 PB 级

  2. 高吞吐访问(RDMA + Direct I/O 的组合优势)

    • RDMA 网络提供 100Gbps+ 带宽和 μs 级延迟,相比 TCP/IP 网络延迟降低 10 倍

    • Direct I/O 绕过内核缓存,使 4KB 随机读取延迟稳定在 20μs 以内(传统方案受内核调度影响可能达 100μs+)

    • 实测数据:在 8 节点集群中实现 800GB/s 聚合带宽,满足千卡集群的 KV 读取需求

  3. 一致性保障(CRAQ 协议的独特价值)

    • 链式复制确保所有存储节点数据强一致,避免多副本场景下的数据版本冲突

    • 写操作通过链式提交(Node1→Node2→…→NodeN),读操作可从任意副本读取最新已提交数据

    • 对比实验:在 10% 写负载下,CRAQ 的读取吞吐比 Raft 高 3.2 倍

    • 和原始的CRAQ不同,3FS的实现并没有去tail target上去查询确认版本信息。而是提供了两个选项:

      1. 直接返回给客户端一个special status code,用户等一段时间后去重试。

      2. 客户端对数据一致性要求不敏感,可以直接返回pending version版本的数据给客户端。

    • 利用RDMA,解除CPU占用

  4. 小文件

    • FFRecord

      • 避免大量的小文件,所有的样本数据在一个或多个大文件里
  5. 其他优化

    • 数据读取模式适配:任何任务从3FS上读取数据,要尽可能让64个存储服务节点能同时读取数据,进而降低单存储节点的带宽需求。我们把块大小缩小到 512KB,并且增加了一个文件分布到的服务器数目的控制,最终成功解决了这个问题。
    • 流量分类控制:infiniband,进行分类,将流量打满
    • 客户端内存优化:减少用户态内核态拷贝

1.6 3FS-KV接口

1.6.1 概览

  • 接入vllm

  • 类似kv,通过USRBIO接口

  • kvcache index(meta data)放在内存中

    • 周期性更新,但是不需要保证最新,因为可以通过计算获取

    • 也要持久化

  • kvcache data放在3FS中,通过USRBIO访问

  • 官方文档3FS/src/lib/api/UsrbIo.md at main · deepseek-ai/3FS

架构图可以参考DeepSeek 3FS 架构分析和思考(上篇) - 文章 - 开发者社区 - 火山引擎

特点:

  • 只对data负责,metadata优先存放在内存中

  • 允许多进程并发提交任务,但是只有3fs自己才可以写入cqe(因此cqe的sem是设计在进程空间内部的,sqe的sem可以通过文件获取)

  • 用户预先指定ring buffer大小

  • sqe和cqe中只有指针,通过共享内存来减少fuse进程与用户进程数据拷贝

1.6.2 入口

  • python接口:hf3fs_fuse/io.py

  • USRBIO原本接口:src/lib/api/hf3fs_usrbio.h

提供iov和ior接口,但是其中Hf3fsIorHandle被置为void*

图片

1.6.3 数据结构设计

图片

IoRing实现位置:3FS/src/fuse/IoRing.h at 0fd4d9b308f0d7632c6566a881d0fc9ee0584708 · deepseek-ai/3FS

允许并发提交,不允许并发准备(初始化)

1.6.4 流程

例子:3FS/src/lib/api/UsrbIo.md at 0fd4d9b308f0d7632c6566a881d0fc9ee0584708 · deepseek-ai/3FS

  1. 调用hf3fs_iovcreate/hf3fs_iovopen/hf3fs_iovwrap来初始化iov区域

  2. ->调用hf3fs_iovcreate_general初始化iov区域,取决于是否是numa分配的

  3. 调用hf3fs_iorcreate创建ior

  4. ->调用hf3fs_iorwrap包装Hf3fsIorHandle

  5. ->调用IoRing初始化buffer,其中通过ringMarkerSize()对齐,然后前四个分别是sqe的头尾和cqe的头尾。然后根据传入的size初始化后面size大小的sqe和cqe的entries。然后初始化cqe的sem

  6. ->调用cqeSem初始化Hf3fsIorHandle中的submit_sem,submit_sem将从文件中读取,因此其为共享的

  7. 调用hf3fs_reg_fd将mount文件传递给3fs

  8. 调用hf3fs_prep_io将数据指针拷贝到sqe中(ring.addSqe())

  9. 调用hf3fs_submit_ios提交io请求(通过submit_sem通知3fs提交)

  10. 调用hf3fs_wait_for_ios等待处理完成(循环等待,一旦完成就拷贝,并调用hf3fs_submit_ios通知3fs更新cqe中的available slots

实现中使用了协程,参考Folly Coroutines Cancellation 的实现 | SF-Zhou’s Blog

2. 思考

2.1 分层kv-cache

3FS提供kv-cache的来源,本地nvme作为kv-cache的缓存,一级位于显存中。使用类似vllm的方式加载或分配kv-cache。

2.2 向量索引

使用向量数据库索引,根据索引拉取3FS的kvcache。

2.2.1 基于树的索引

  • KD-Tree (K-Dimensional Tree)

    • 原理:递归地将数据空间沿坐标轴分割成超矩形区域,构建二叉树。

    • 优点:适合低维数据(维度 < 20),支持精确搜索。

    • 缺点:高维数据性能急剧下降(“维度灾难”)。

    • 应用场景:小规模低维数据集(如地理坐标搜索)。

  • Ball Tree

    • 原理:将数据划分为嵌套的超球体,减少距离计算次数。

    • 优点:相比 KD-Tree,在高维数据中表现更好。

    • 缺点:构建和查询成本较高,适合中等维度。

    • 应用场景:中等维度数据(如特征向量分类)。

  • Annoy (Approximate Nearest Neighbors Oh Yeah)

    • 原理:通过随机投影构建多棵树,利用投票机制提升搜索效率。

    • 优点:内存占用低,支持并行查询。

    • 缺点:需要调参(树的数量、搜索节点数)。

    • 应用场景:中等规模高维数据(如 Spotify 音乐推荐)。

2.2.2 基于哈希的索引

LSH (Locality-Sensitive Hashing)

  • 原理:通过哈希函数将相似向量映射到相同桶中,牺牲精度换速度。

  • 优点:查询速度快,适合超大规模数据。

  • 缺点:参数敏感,召回率较低。

  • 变体:Multi-probe LSH(提升召回率)。

  • 应用场景:海量数据快速粗筛(如去重、预过滤)。

2.2.3 基于图的索引

  • HNSW (Hierarchical Navigable Small World)

    • 原理:构建多层图结构,上层为稀疏图用于快速导航,下层为稠密图用于精细搜索。

    • 优点:高召回率、低延迟,支持动态更新。

    • 缺点:内存占用较高。

    • 应用场景:高性能实时搜索(如 Milvus、Elasticsearch)。

  • NSW (Navigable Small World)

    • 原理:单层图结构,通过贪心算法逐步逼近目标节点。

    • 优点:实现简单,适合中小规模数据。

    • 缺点:性能随数据量增长下降明显。

    • 应用场景:小规模实时搜索。

2.2.4 基于量化的索引

  • PQ (Product Quantization)

    • 原理:将高维向量切分为子向量,分别量化并构建码本,用笛卡尔积压缩向量。

    • 优点:大幅减少内存占用,适合超大规模数据。

    • 缺点:量化误差可能影响精度。

    • 应用场景:大规模图像检索(如 Facebook Faiss)。

  • IVF (Inverted File Index)

    • 原理:先聚类(如 K-Means),再对每个簇构建倒排索引,搜索时仅遍历最近簇。

    • 优点:结合聚类加速,适合非均匀分布数据。

    • 缺点:聚类质量影响性能。

    • 变体:IVF-PQ(结合量化进一步压缩)。

    • 应用场景:大规模相似性搜索(如 Faiss 的 IVF 系列)。

2.3.5 混合与优化方案

  • SCANN (Scalable Nearest Neighbors)

    • 原理:结合树、哈希和量化,动态选择最优搜索路径。

    • 优点:平衡速度与精度,适合超大规模数据。

    • 应用场景:Google 的大规模向量检索。

  • DiskANN

    • 原理:结合图索引与磁盘存储优化,减少内存依赖。

    • 优点:支持内存受限场景。

    • 应用场景:十亿级数据检索(如微软 Bing 搜索)。

2.3 milvus

  • 利用其他数据库、消息中间件、向量算法库构建向量数据库

  • 提供分片能力:分shard(自动)、partition(通过键值分区)、segment(最小粒度)

  • 逻辑:

    • slow path:先放入DataNode存储,然后离线转入IndexNode构建索引,构建结束之后转入QueryNode提供查询服务

    • fast path:直接转入QueryNode提供查询服务

v2-524abb99eba02c545caf5b093bfc9b3e_1440w

v2-8c4145ee4528ae85fe7a887af2068bc5_1440w

参考

deepseek-ai/3FS: A high-performance distributed file system designed to address the challenges of AI training and inference workloads.

3FS/docs/design_notes.md at main · deepseek-ai/3FS

一文快速入门 ClickHouse - 知乎

Folly Coroutines Cancellation 的实现 | SF-Zhou’s Blog

幻方力量 | 高速文件系统 3FS

Deepseek开源第五炮:3FS文件系统详解 - 知乎

DeepSeek 3FS:端到端无缓存的存储新范式 - 知乎

DeepSeek Fire-Flyer File System(3FS) - 知乎

DeepSeek开源周 Day05:从3FS盘点分布式文件存储系统-腾讯云开发者社区-腾讯云

DeepSeek:3FS系统介绍 - 知乎

DeepSeek 3FS 架构分析和思考(上篇) - 文章 - 开发者社区 - 火山引擎

DeepSeek文件系统3FS设计文档-中文翻译-解读_deepseek 3fs 设计文档-CSDN博客

RAG搭建中,如何选择最合适的向量索引? - Zilliz 向量数据库

向量数据库(三)向量数据库的底层架构及HNSW等索引算法讲解 - 星环开发者社区

1W2000字 一文读懂向量数据库:原理、索引技术与选型指南 - 知乎

LLM-向量数据库中的索引算法总结_向量数据库索引-CSDN博客

向量数据库(第 3 部分):并非所有索引都是一样的 - 知乎

草履虫都看得懂的向量数据库教程,一文就够了_向量数据库使用-CSDN博客

前所未有的 Milvus 源码架构解析 - 知乎

数据处理 | Milvus 文档

为AI而生的数据库:Milvus详解及实战_向量数据库 milvus-CSDN博客

快速入门 | Milvus 文档

云原生向量数据库Milvus知识大全,看完这篇就够了[基本概念、系统架构、主要组件、应用场景]-腾讯云开发者社区-腾讯云

Milvus - 架构设计详解-CSDN博客

Milvus向量数据库全面解析:架构、原理与实践指南-百度开发者中心

Milvus 架构概述 – Milvus向量库中文文档

FFRecord | 高性能训练数据格式

3FS优化 03 | 数据读取模式适配

3FS优化 03 | 网络配置管理

3FS优化 02 | 客户端内存使用优化

How does KVCache Client works on 3FS? · Issue #109 · deepseek-ai/3FS

陈巍:DeepSeek 开源Day(5)3FS&smallpond深入分析(收录于:DeepSeek技术详解系列) - 知乎

3FS/src/lib/rs/hf3fs-usrbio-sys/src/lib.rs at main · deepseek-ai/3FS

3FS系列(三):从源码到实测:3FS USRBIO静态库的编译与性能体验 | 机器之心

3FS/src/lib/api/UsrbIo.md at main · deepseek-ai/3FS

DeepSeek 3FS解读与源码分析(5):客户端解读_usrbio-CSDN博客

3FS/hf3fs_fuse/io.py at 0fd4d9b308f0d7632c6566a881d0fc9ee0584708 · deepseek-ai/3FS

3FS/src/lib/api/hf3fs_usrbio.h at 0fd4d9b308f0d7632c6566a881d0fc9ee0584708 · deepseek-ai/3FS

3FS/src/fuse/IoRing.h at 0fd4d9b308f0d7632c6566a881d0fc9ee0584708 · deepseek-ai/3FS

3FS/src/lib/api/UsrbIo.cc at 0fd4d9b308f0d7632c6566a881d0fc9ee0584708 · deepseek-ai/3FS

SF-Zhou’s Blog

Folly Coroutines Cancellation 的实现 | SF-Zhou’s Blog

AI训练存储方案选谁?DeepSeek 3FS与JuiceFS的全面对比|调用|磁盘|拷贝|元数据|ai训练|inode|命令提示符_网易订阅

  • Title: 3fs learning
  • Author: Ethereal
  • Created at: 2025-04-12 15:16:42
  • Updated at: 2025-05-15 12:38:38
  • Link: https://ethereal-o.github.io/2025/04/12/3fs-learning/
  • License: This work is licensed under CC BY-NC-SA 4.0.
 Comments