从⻘铜到王者系列:深⼊浅出理解DeepSeek 3FS (2)从内核到⽤⼾态⽂件系统的设计之路
⼤家好,我是⼩王同学,本⽂希望帮你深⼊理解分布式存储系统3FS更进⼀步
昵称:20点下班就是⼀件很幸福事情愿景:让⼩孩都可以听得懂我在讲什么。我能提供什么:多问⾃⼰⼀次为什么这样⽤
作业 实现 hello world 的⽂件系统 ,并说出IO流程
参考答案
/
.c 没有FUSE的IO流程⽰意图
带FUSE的IO流程⽰意图
⼀、导读
从⻘铜到王者系列:深⼊浅出理解 DeepSeek 3FS(1)我整理 ⼤模型训练
在checkpoint时候对⼤的⽂件读写,在批量查询的时候对⼩⽂件读写
⽬前
⾕歌的GFS 适合 ⼤⽂件顺序读写,
Ceph mds 元数据 存在瓶颈 8k作⽤
幻⽅为什么要搞3FS?
AI训练与推理的业务需求,传统分布式⽂件系统已经难以满⾜:
- 海量数据顺序读(语料输⼊)
- 检查点(分步骤重算)
- 顺序写(模型参数保存);
- 随机读
因此重新实现⼀个新的⽂件系统
不考虑分布式,个⼈笔记或者购买云主机⽂件系统如何⽀持⼤⼩⽂件读写,并且满⾜⾼效查询提问:Linux 系统启动过程划重点:重点是⽂件系统部分,扩展虚拟机(KVM)与内核部分。
电脑通电后,加载主板上的BIOS(basic input output system)程序
BIOS是电脑启动时加载的第⼀个软件。
它是⼀组固化到计算机内主板上⼀个ROM芯⽚上的程序 boot:
虚拟机(KVM)如何设置引导硬盘顺序
什么是 KVM?
基于内核的虚拟机(KVM)是 Linux® 操作系统的⼀种开源虚拟化技术。借助
KVM,Linux 可作为虚拟机监控程序运⾏多个独⽴的虚拟机(VM)
BIOS--》boot
第1引导顺序:hard drive 硬盘第2引导顺序:cdrom 光驱 ----》安装系统第3引导顺序:removable device 可移动设备--》u盘,移动硬盘 --》安装系统第4引导顺序:Network --》从⽹络启动--》⽹络中安装服务器启动 --》安装
⽂件系统部分
启动流程:
- 内核加载完成
- 执⾏mount操作
挂载⽂件系统想要操作⽂件系统,第⼀件事情就是挂载⽂件系统
- 读取超级块
- 定位inode 2
- 将其挂载为根⽬录系统启动过程:
+----------------+ +---------------+ +------------------+
| 读取超级块 | --> | 定位inode 2 | --> | 挂载为根目录(/) |
+----------------+ +---------------+ +------------------+
在 Linux 启动过程中,加载 ext4 ⽂件系统主要经历以下⼏个阶段:
- 内核加载与初始化当系统通过 BIOS/UEFI 加载引导加载程序(如 GRUB)后,内核被加载到内存中。
内核初始化时,会建⽴ VFS(虚拟⽂件系统)核⼼数据结构,如 dentry 哈希表和 inode 哈希表,并加载必要的⽂件系统驱动(ext4 驱动可以是内置的或作为模块加载)。
- 挂载根⽂件系统内核根据启动参数(例如 root=/dev/sda1)确定根⽂件系统所在的设备。调⽤函数如 vfs_kern_mount()(进⼀步调⽤ ext4_mount())来挂载 ext4
⽂件系统。
在挂载过程中,ext4 驱动会读取设备上的超级块(superblock),验证
ext4 的魔数(magic number)和其它元数据,同时初始化 inode 表、⽇志(journal)等内部数据结构。
ext4 ⽂件系统的根⽬录在挂载时根据约定总是分配 inode 号 2。
- 切换根⽂件系统(pivot_root/switch_root)如果系统使⽤了 initrd 或 initramfs 作为临时根⽂件系统,内核会在加载完真正的 ext4 ⽂件系统后,通过 pivot_root 或 switch_root 将根⽬录切换到挂载的 ext4 ⽂件系统上。
此时,init(或 systemd)进程启动,⽤⼾空间接管并继续后续的初始化⼯作。
这样,整个过程确保了 ext4 ⽂件系统的元数据和数据块被正确加载,并最终成为系统的根⽂件系统,使⽤⼾和应⽤程序可以正常访问⽂件数据。
作业:为什么不同挂载点的inode号码都是2
⼆、提问:Linux ⽂件系统是怎么⼯作的?
通过这张图,你可以看到,在 VFS 的下⽅,Linux ⽀持各种各样的⽂件系统,如
Ext4、XFS、NFS 等等。按照存储位置的不同,这些⽂件系统可以分为三类。
类是基于磁盘的⽂件系统,也就是把数据直接存储在计算机本地挂载的磁盘中。
⻅的 Ext4、XFS、OverlayFS 等,都是这类⽂件系统。
类是基于内存的⽂件系统,也就是我们常说的虚拟⽂件系统。
类是⽹络⽂件系统,
也就是⽤来访问其他计算机数据的⽂件系统,⽐如 NFS、SMB、iSCSI 等。
⽹络⽂件系统 NFS:⾸次突破内核态
随着计算需求的增⻓,单台计算机的性能逐渐⽆法满⾜⽇益增⻓的计算和存储要求。
⼈们开始引⼊多台计算机,以分担负载并提⾼整体效率。
在这⼀场景下,⼀个应⽤程序往往需要访问分布在多台计算机上的数据。
为了解决这⼀问题,⼈们提出了在⽹络中引⼊虚拟存储层的概念,将远程计算机的⽂件系统(如某个⽬录)通过⽹络接⼝挂载到本地计算机的节点上。
这样做的⽬的是使本地计算机能够⽆缝地访问远程计算机的数据,就好像这些数据存储在本地⼀样
linux分析利刃之sar命令详解
参考:
.html
sar -n DEV 1 1#统计⽹络信息 这个有⽤带宽统计查看进⾏哪些线程
⽂件系统的格式
来源:
第四代扩展⽂件系统(英语:Fourth extended filesystem,缩写为ext4)是Linux 系统下的⽇志⽂件系统
⽂件系统(六):⼀⽂看懂linux ext4⽂件系统⼯作原理
ext4它突出的特点有:数据分段管理、多块分配、延迟分配、持久预分配、⽇志校验、⽀持更⼤的⽂件系统和⽂件⼤⼩。
ext4⽂件系统的具体实现⽐较复杂,本⽂尝试⽤⽐较简单的⽅式⽤⼀篇⽂章的篇幅来简单地介绍⼀下它的⼯作原理。
命令:dumpe2fs /dev/loop0
从上⾯dumpe2fs的数据上我们可以看出,⼀个1GB⼤⼩的空间,ext4 ⽂件系统将它分隔成了0~7的8个Group。
其中,每个Group中⼜有superblock、Group descriptors、bitmap、Inode table、
usrer data、还有⼀些保留空间,细分之后的空间布局如下: ext4 的总体磁盘布局如下:
具体含义内:
ext4⽂件系统信息表
从上⾯《1.1 ext4⽂件系统信息表》中可以知道Primary superblock在第0号 block,每个block的⼤⼩为4096Byte
⽂件系统信息、块⼤⼩和块组信息、Inode 相关信息、⽂件系统⼤⼩和使⽤情况、⽇志相关信息、挂载信息、校验和和备份信息。
这⾥⾯我还需要重点说⼀下,超级块和块组描述符表都是全局信息,⽽且这些数据很重要。
如果这些数据丢失了,整个⽂件系统都打不开了,这⽐⼀个⽂件的⼀个块损坏更严重。所以,这两部分我们都需要备份,但是采取不同的策略。默认情况下,超级块和块组描述符表都有副本保存在每⼀个块组⾥⾯
其实使⽤dumpe2fs命令查看的ext4⽂件系统信息就是从superblock上的数据解析
⽽来。
除了Primary superblock,还在不同的group中有备份superblock,其内容与
Primary superblock原始数据相同,Primary superblock损坏的时候可以从备份区恢复回来
回顾:
在 Linux 内核挂载 ext4 ⽂件系统时,挂载流程⼤致如下:
- 系统调⽤ mount() 启动挂载流程当⽤⼾或内核启动参数(如 root=/dev/sda1)触发挂载时,会调⽤通⽤的 mount 系统调⽤,进⽽进⼊ VFS 层的挂载流程。
- 进⼊ ext4 挂载⼊⼝ ext4_mount()
ext4 ⽂件系统在内核中注册为⼀种⽂件系统类型,其挂载⼊⼝函数通常为 ext4_mount()(定义在 fs/ext4/super.c 中)。
在该函数中,会调⽤ ext4_fill_super(),⽤来读取磁盘上的超级块
(superblock)并验证 ext4 ⽂件系统的完整性。
- 解析超级块与加载根 inode ext4_fill_super() 会从设备上读取超级块数据,然后填充超级块结构体。在超级块中保存了⽂件系统全局信息,其中就包括 ext4 ⽂件系统的根⽬录 inode 的固定编号(EXT4_ROOT_INO 定义为 2,⻅ fs/ext4/ext4.h)。紧接着,内核通过 ext4_iget()(或相关函数)加载 inode 2,这个 inode 就代表了⽂件系统的根⽬录。
- 构造根⽬录 dentry 并完成挂载加载根 inode 后,内核会创建相应的 dentry(⽬录项),并将该根 dentry 作为挂载点的根,最终将整个⽂件系统挂载为根⽬录(/)。
相关源码主要分布在内核源代码的 fs/ext4/ ⽬录下,具体可以查看 ext4_mount()、ext4_fill_super() 以及 ext4_iget() 等函数。
ext4 ⽂件系统特点的
具体如何保存的呢?
EXT4_N_BLOCKS 有如下的定义,计算下来⼀共有 15 项。在 ext2 和 ext3 中,其中前 12 项直接保存了块的位置,也就是说,我们可以通过 i_block[0-11],直接得到保存⽂件内容的块。
如果⼀个⽂件⽐较⼤,12 块放不下 i_block[12]指向⼀个块,这个块⾥⾯不放数据块,⽽是放数据块的位置,这个块我们称为间接块。
也就是说,我们在 i_block[12]⾥⾯放间接块的位置,通过 i_block[12]找到间接块后,间接块⾥⾯放数据块的位置,通过间接块可以找到数据块。如果⽂件再⼤⼀些,i_block[13]会指向⼀个块,我们可以⽤⼆次间接块【指针的指针】
如果⽂件再⼤⼀些,i_block[14]会指向三次间接块
EXT4 ⽂件系统采⽤ 索引节点(inode)结构 来管理⽂件,其中 inode 结构中包含 15 个指针,⽤于定位⽂件数据块。 EXT4 Inode 结构中的 15 个指针
指针类型 | 数量 | 说明 |
---|---|---|
直接块指针(Direct Block) | 12 | 直接指向数据块,每个指针可寻址 1 个数据块。 |
⼀次间接指针(Singly Indirect) | 1 | 指向⼀个块,该块内存储多个直接块指针。 |
⼆次间接指针(Doubly Indirect) | 1 | 指向⼀个块,该块内的指针指向多个⼀次间接块。 |
三次间接指针(Triply Indirect) | 1 | 指向⼀个块,该块内的指针指向多个⼆次间接块。 |
单个⽂件最⼤⽀持⼤⼩计算
假设 块⼤⼩(block size)为 4KB(EXT4 常⽤设置),计算单个⽂件最⼤⼤⼩:
- 直接块存储数据:
12 个直接指针 × 4KB = 48KB
- ⼀次间接块存储数据:
- 个指针块存储 1024 个指针(4KB / 4B = 1024)
1024 × 4KB = 4MB
- ⼆次间接块存储数据:
- 个指针块存储 1024 个⼀次间接指针
1024 × 4MB = 4GB
- 三次间接块存储数据:
- 个指针块存储 1024 个⼆次间接指针
1024 × 4GB = 4TB
最终计算(最⼤单个⽂件⼤⼩)
直接块:48KB
⼀次间接块:4MB ⼆次间接块:4GB 三次间接块:4TB
总计 ≈ 4TB + 4GB + 4MB + 48KB ≈ 4TB
结论
EXT4 单个⽂件最⼤可达 16TB(如果启⽤了 更⼤的 block size,⽐如
64KB)。
在 4KB 块⼤⼩下,单个⽂件最⼤ ≈ 4TB(由于索引结构限制)。
相⽐ EXT3(单⽂件最⼤ 2TB),EXT4 更适合⼤⽂件存储。
如果需要存储超过 4TB 的单个⽂件,可以:
- 使⽤更⼤的块⼤⼩(如 64KB,最⼤ 16TB)。
- 考虑使⽤其他⽂件系统(如 XFS、Btrfs、ZFS)。
对⽐:
为了解决这个问题,ext4 做了⼀定的改变。
它引⼊了⼀个新的概念,叫做 Extents。
我们来解释⼀下 Extents。
⽐⽅说,⼀个⽂件⼤⼩为 128M,如果使⽤ 4k ⼤⼩的块进⾏存储,需要 32k 个块。
如果按照 ext2 或者 ext3 那样散着放,数量太⼤了。
但是 Extents 可以⽤于存放连续的块,也就是说,我们可以把 128M 放在⼀个
Extents ⾥⾯。
这样的话,对⼤⽂件的读写性能提⾼了,⽂件碎⽚也减少了。
除了根节点,其他的节点都保存在⼀个块4k⾥⾯,4k扣除ext4_extent_header的 12个byte,剩下的能够放340项,每个extent最⼤能表⽰128MB的数据,340个 extent会使你的表⽰的⽂件达到42.5GB。
三、ext4⽂件系统为例⼦ cat /mnt/icfs/fileA 判断⽂件fileA是否存在
✅前置条件:
在 Linux 中,⽂件系统(如 ext4)通常只能在块设备(block device)上创建和操
作,例如:
物理磁盘 (/dev/sda, /dev/nvme0n1) 磁盘分区 (/dev/sda1, /dev/nvme0n1p1) 虚拟块设备(如 LVM 逻辑卷 /dev/mapper/vg-lv)
如果 没有额外的磁盘,但你仍然需要:
发布评论