磁盘明明还剩几十个GB,创建个大文件却提示“No space left on device”;删了一个好几GB的日志,df -h 一看,可用空间纹丝不动。如果你在 Linux 上遇到过这种让人抓狂的场面,那说明你对“存储堆栈”的理解还停留在表面。这篇内容,就是想带你把这个堆栈从头到尾捋一遍。
这里不罗列命令大全,而是站在一个常年跟 Linux 服务器打交道的运维视角,把块设备、分区、文件系统、挂载点、IO 调度这些概念串起来,讲清楚一个文件从写入到底层磁盘之间发生了什么,以及当空间消失、IO 飙升时应该怎么排查。无论你是刚接触 Linux 的新手,还是被存储问题折磨过的初级运维,这篇文章都值得花十分钟读完——读完你至少能搞懂系统提示“磁盘满”时,到底是谁满了。
1. 一张图看懂存储堆栈:从硬件到应用经历了什么
很多人把 Linux 的存储管理理解成“分个区、格个盘、挂载一下”,这没错,但这只是最外层操作。实际上,一个写操作从应用程序发起,到真正落到磁盘的磁道上,中间至少经过五六个层次。理解这个层次结构,后面所有的排查和调优才有依据。
1.1 存储堆栈的五个核心层次
从下往上看,整个存储堆栈可以这样拆:
- 物理设备层:这是最底层的硬件,包括 SATA/SAS 硬盘、NVMe SSD、U 盘、SD 卡等。操作系统通过驱动识别它们,并在
/dev目录下生成对应的设备文件,比如/dev/sda、/dev/nvme0n1。 - 块设备层:Linux 把物理设备抽象成块设备,这是内核与硬件交互的统一接口。块设备以固定大小的块为单位读写,通常 512 字节或 4K。这一层还负责 IO 调度——也就是决定先处理哪个读写请求。
- 分区与设备映射层:在块设备之上,你可以把一整块磁盘划分成多个分区(
/dev/sda1、/dev/sda2),也可以通过 LVM、RAID、dm-crypt 等机制做逻辑卷管理、磁盘冗余或加密。这一层是灵活的,普通场景可以跳过,但生产环境基本绕不开。 - 文件系统层:这一层负责把块设备组织成目录树,管理文件名、权限、元数据。Linux 上常见的有 ext4、XFS、Btrfs、ZFS 等,各有各的适用场景。
- 虚拟文件系统层(VFS):这是 Linux 内核提供给用户空间程序的统一接口。不管你底层用的是 ext4 还是 XFS,
open()、read()、write()这些系统调用长得一模一样。VFS 还会维护页缓存(Page Cache),这也是后面要讲的“删了文件空间不释放”的根源之一。
1.2 一个写请求的完整旅行
举个实际的例子。你在终端执行:
bash复制echo "hello" > /mnt/data/test.txt
这条命令背后发生的事情是:
- shell 调用
write()系统调用,把“hello\n”这个字符串交给 VFS。 - VFS 检查文件权限和页缓存。如果数据不大,大概率不会立刻写磁盘,而是先写进 Page Cache,标记为脏页。
- 脏页在后台由
pdflush(老内核)或writeback机制刷到文件系统层。 - 文件系统把逻辑偏移量翻译成块设备上的物理块地址,通过块设备层提交 IO 请求。
- 块设备层的 IO 调度器对请求排序、合并,发给驱动。
- 驱动把命令发给磁盘固件,磁盘完成读写。
你看,用户态程序跟硬件之间隔了这么多层。每一层都可能出问题——文件系统满了、inode 耗尽了、块设备只读挂载了、磁盘本身坏了、页缓存太多导致写不进去。理解了这条链路,你排查问题时就能按层定位,而不是瞎猜。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 先从底层说起:块设备、分区和系统盘命名
这一节把第一层和第二层铺开讲。很多新手最容易困惑的就是盘符命名:为什么有的叫 /dev/sda,有的叫 /dev/vda,还有的叫 /dev/nvme0n1p1?搞懂这个,后续操作才不会对着错设备执行命令。
2.1 设备命名规则背后的历史包袱
Linux 的设备命名看起来乱,其实有迹可循:
| 设备类型 | 命名示例 | 说明 |
|---|---|---|
| 老式 IDE 硬盘 | /dev/hda, /dev/hdb | 现在已经很少见 |
| SATA/SCSI 硬盘 | /dev/sda, /dev/sdb | 字母 a 表示第一块,b 表示第二块 |
| 虚拟化环境磁盘 | /dev/vda, /dev/vdb | virtio 驱动,常见于 KVM 虚拟机 |
| NVMe SSD | /dev/nvme0n1, /dev/nvme0n2 | 控制器编号+命名空间编号 |
| SD/MMC 卡 | /dev/mmcblk0 | 树莓派、嵌入式设备常见 |
| LVM 逻辑卷 | /dev/mapper/vg-lv | 或 /d |
