专栏文章
专栏文章
Linux 专栏
1. Linux 专栏 #01:进程与线程 2. Linux 专栏 #02:内存管理 3. Linux 专栏 #03:文件系统 4. Linux 专栏 #04:网络与 IO 模型 5. Linux 专栏 #05:中断机制 6. Linux 专栏 #05:性能分析工具 7. Linux 专栏 #06:eBPF 技术实战

Linux 专栏 #03:文件系统

发布于 2026-06-08 07:30 👁 5 次阅读
#操作系统#linux

文件系统

Linux "一切皆文件"的设计哲学通过 VFS(虚拟文件系统)抽象层实现。理解 inode/dentry 结构、Page Cache 工作原理以及各种 I/O 模式,是优化 Java/Go 服务磁盘 I/O 性能的前提。


目录

章节 说明
文件系统层次结构 VFS → 具体文件系统 → 块设备
inode 与 dentry 文件元数据与目录结构
软链接 vs 硬链接 本质区别与使用场景
文件 I/O 分类 缓冲/直接/阻塞/异步
Page Cache 工作原理 读写缓存机制
常用文件操作命令 find/grep/awk/sed 速查

文件系统层次结构

应用程序(open/read/write 系统调用)
         ↓
   VFS(虚拟文件系统)
   统一接口:inode/dentry/file/super_block
         ↓
  ┌──────┬──────┬──────┬──────┐
  │ ext4 │ xfs  │ NFS  │/proc │  具体文件系统
  └──────┴──────┴──────┴──────┘
         ↓
   通用块层(Block Layer)
   I/O 调度器(CFQ/Deadline/NOOP)
         ↓
   块设备驱动(SCSI/NVMe)
         ↓
   物理磁盘

文件系统三大类

类型 代表 说明
基于磁盘 ext4、xfs、btrfs 数据持久化到本地磁盘
基于内存 /proc、/sys、tmpfs 不占磁盘,内核动态构建
网络文件系统 NFS、CIFS 访问远程机器数据
# 查看已挂载的文件系统
df -hT
mount | column -t

# 查看磁盘空间使用
df -h
# 查看 inode 使用情况(inode 耗尽也会导致"磁盘满")
df -i

inode 与 dentry

inode(索引节点)

每个文件对应一个 inode,记录文件的元数据(不含文件名):

字段 内容
inode 编号 文件系统内唯一标识
文件大小 字节数
权限 rwxrwxrwx + 特殊位
时间戳 atime/mtime/ctime
硬链接计数 指向该 inode 的目录项数量
数据块指针 指向实际存储数据的磁盘块
# 查看文件的 inode 信息
stat filename
ls -i filename      # 显示 inode 编号

# 根据 inode 编号查找文件
find /path -inum <inode_number>

dentry(目录项)

记录文件名与 inode 的映射关系,由内核在内存中维护(目录项缓存)。

关系:一个 inode 可对应多个 dentry(硬链接),一个 dentry 只指向一个 inode。

inode dentry


软链接 vs 硬链接

维度 硬链接 软链接(符号链接)
本质 新的目录项指向同一 inode 新的文件,内容是目标路径字符串
inode 相同 不同
跨文件系统 不支持 支持
目录 不支持(防止循环) 支持
原文件删除后 仍可访问(inode 引用计数 > 0) 变成悬空链接(dangling link)
命令 ln src dst ln -s src dst
# 创建硬链接
ln original.txt hardlink.txt
ls -li original.txt hardlink.txt   # inode 编号相同

# 创建软链接
ln -s /etc/nginx/nginx.conf nginx.conf
ls -la nginx.conf                  # 显示 -> 目标路径

# 查找所有悬空软链接
find /path -type l -xtype l

文件 I/O 分类

四个维度

维度 1:是否使用标准库缓冲

类型 说明 场景
缓冲 I/O 通过 glibc 的用户态缓冲区(fread/fwrite) 大多数场景,减少系统调用次数
非缓冲 I/O 直接系统调用(read/write) 需要精确控制数据时机

维度 2:是否绕过 Page Cache

类型 说明 场景
非直接 I/O(默认) 经过 Page Cache 普通文件读写,利用缓存加速
直接 I/O(O_DIRECT) 绕过 Page Cache 数据库(MySQL InnoDB)自管缓存

维度 3:是否阻塞调用线程

类型 说明
阻塞 I/O 等待 I/O 完成才返回,线程挂起
非阻塞 I/O(O_NONBLOCK) 立即返回,未就绪时返回 EAGAIN

维度 4:通知方式

类型 说明
同步 I/O 调用方等待 I/O 完成
异步 I/O(AIO) 提交请求后立即返回,完成后通过事件/回调通知
阻塞 I/O:      应用 ──────────────────────→ 返回
                      等待数据 + 等待复制

非阻塞 I/O:    应用 → 查询 → EAGAIN(未就绪)
                      → 查询 → EAGAIN
                      → 查询 → 数据就绪 → 复制 → 返回

I/O 多路复用:  应用 → select/poll/epoll 监听多个 fd
                      → 有 fd 就绪 → read → 返回

异步 I/O:      应用 → aio_read() → 立即返回
                      → 内核完成后发信号/回调通知

Page Cache 工作原理

Page Cache 是 Linux 内核用内存缓存磁盘文件内容的机制,大幅减少磁盘 I/O。

读流程

read() 系统调用
    ↓
检查 Page Cache 是否有对应页
    ├── 命中(Cache Hit)→ 直接从内存返回
    └── 未命中(Cache Miss)→ 从磁盘读入内存 → 更新 Page Cache → 返回

写流程(默认:写回模式 Write-Back)

write() 系统调用
    ↓
写入 Page Cache(内存),标记为"脏页"(dirty)
    ↓
立即返回(不等待磁盘写入)
    ↓
内核后台 pdflush/kworker 线程定期将脏页刷入磁盘

强制刷盘

sync                          # 刷所有脏页
fsync(fd)                     # 刷指定文件(含元数据)
fdatasync(fd)                 # 刷数据,不刷元数据(更快)

查看 Page Cache

# 查看 buff/cache 大小
free -h

# 查看 Page Cache 详情
cat /proc/meminfo | grep -E "Cached|Buffers|Dirty|Writeback"

# 手动清理 Page Cache(生产环境谨慎)
echo 1 > /proc/sys/vm/drop_caches   # 清理 Page Cache
echo 2 > /proc/sys/vm/drop_caches   # 清理 slab(dentry/inode 缓存)
echo 3 > /proc/sys/vm/drop_caches   # 清理 Page Cache + slab

Buffer vs Cache

类型 用途
Buffer 块设备的原始数据缓存(写操作)
Cache 文件系统的页缓存(读操作为主)

常用文件操作命令

find — 文件查找

# 按名称查找
find /var/log -name "*.log"

# 按修改时间(最近 7 天修改的)
find /home -mtime -7

# 按大小(大于 100MB)
find /data -size +100M

# 按类型(只找目录)
find /etc -type d -name "nginx*"

# 找到后执行操作(删除 30 天前的日志)
find /var/log -name "*.log" -mtime +30 -exec rm {} \;

# 排除目录
find /data -path /data/backup -prune -o -name "*.txt" -print

grep — 内容搜索

# 递归搜索(常用)
grep -r "OutOfMemoryError" /var/log/

# 显示行号、前后上下文
grep -n -A 3 -B 3 "ERROR" app.log

# 忽略大小写
grep -i "exception" app.log

# 统计匹配行数
grep -c "ERROR" app.log

# 反向匹配(不含 DEBUG 的行)
grep -v "DEBUG" app.log

# 多模式匹配
grep -E "ERROR|WARN|FATAL" app.log

awk — 结构化文本处理

# 打印第 2 列(空格分隔)
awk '{print $2}' file.txt

# 条件过滤:第 3 列大于 100
awk '$3 > 100 {print $0}' file.txt

# 统计 HTTP 状态码分布
awk '{print $9}' access.log | sort | uniq -c | sort -rn

# 计算平均响应时间(第 7 列)
awk '{sum+=$7; count++} END {print "avg:", sum/count "ms"}' access.log

# 自定义分隔符(处理 CSV)
awk -F',' '{print $1, $3}' data.csv

sed — 流式文本编辑

# 替换(g 表示全局)
sed 's/old/new/g' file.txt

# 原地修改(-i)
sed -i 's/localhost/127.0.0.1/g' config.properties

# 删除空行
sed '/^$/d' file.txt

# 打印特定行范围
sed -n '10,20p' file.txt

# 在匹配行后插入内容
sed '/\[server\]/a host=127.0.0.1' config.ini

磁盘使用分析

# 按大小排序目录
du -sh /var/* | sort -rh | head -20

# 查找大文件
find / -type f -size +1G 2>/dev/null | xargs ls -lh

# 查看 inode 使用("磁盘满"但 df -h 显示有空间时检查)
df -i
# 找出占用 inode 最多的目录
find /var -xdev -printf '%h\n' | sort | uniq -c | sort -rn | head

参考资料

  • 《趣谈 Linux 操作系统》— 27-30 文件系统系列(刘超,极客时间)
  • 《Linux 性能优化实战》— 22-32 文件系统与磁盘 I/O 模块(倪朋飞,极客时间)
  • man 2 openman 2 readman 2 mmap
← 返回列表

评论 (0)

暂无评论,来留下第一条吧。

发表评论