Skip to content

Latest commit

 

History

History
235 lines (172 loc) · 5.8 KB

File metadata and controls

235 lines (172 loc) · 5.8 KB

1.3 文件系统

📍 导航返回目录 | 上一节:内存管理 | 下一节:网络IO


核心原理

VFS(虚拟文件系统)架构

Linux 通过 VFS 层抽象不同文件系统的实现:

应用层
   ↓
系统调用(open, read, write, close)
   ↓
VFS 层(统一接口)
   ↓
具体文件系统(ext4, xfs, btrfs 等)
   ↓
块设备层
   ↓
硬件驱动

核心数据结构

  • inode(索引节点):存储文件元数据(权限、大小、时间戳、数据块指针等)
  • dentry(目录项):文件名与 inode 的映射关系
  • file(文件对象):进程打开文件的实例

ext4 文件系统

  • Block 大小:通常 4KB
  • inode 结构:直接块(12个)+ 间接块 + 二级间接块 + 三级间接块
  • 日志(Journal):保证文件系统一致性,支持数据、元数据或混合模式
  • 延迟分配:推迟块分配时机,提升性能
  • 多块分配:一次分配多个连续块,减少碎片

文件 IO 模式

  1. 标准 IO:带缓冲,用户态缓存 + 内核页缓存
  2. 直接 IO(Direct IO):绕过页缓存,直接读写磁盘
  3. 内存映射 IO(mmap):将文件映射到进程地址空间
  4. 异步 IO(AIO):非阻塞 IO,提交请求后立即返回

页缓存(Page Cache)

  • 内核使用空闲内存缓存磁盘数据
  • 读操作:优先从页缓存读取
  • 写操作:写入页缓存,后台同步到磁盘
  • 脏页(Dirty Page):被修改但未同步的页缓存

关键命令与工具

# 文件系统信息
df -h                     # 查看磁盘使用情况
df -i                     # 查看 inode 使用情况
mount                     # 查看挂载点
lsblk                     # 列出块设备

# 文件操作
stat file.txt             # 查看文件详细信息
ls -li                    # 显示 inode 号
du -sh /path              # 查看目录大小
find / -size +100M        # 查找大文件

# 磁盘 IO 监控
iostat -x 1               # 监控磁盘 IO 性能
iotop                     # 实时查看进程 IO 使用
dstat -d                  # 综合监控工具

# 文件系统检查与修复
fsck /dev/sda1            # 检查并修复文件系统
tune2fs -l /dev/sda1      # 查看文件系统参数

# 页缓存管理
sync                      # 同步脏页到磁盘
echo 3 > /proc/sys/vm/drop_caches  # 清理页缓存

实战示例:零拷贝文件传输(Go)

package main

import (
    "net"
    "os"
    "syscall"
)

// ZeroCopyFileSend 使用 sendfile 实现零拷贝文件传输
func ZeroCopyFileSend(conn *net.TCPConn, filePath string) error {
    file, err := os.Open(filePath)
    if err != nil {
        return err
    }
    defer file.Close()
    
    fileInfo, err := file.Stat()
    if err != nil {
        return err
    }
    
    // 获取文件描述符
    filefd := int(file.Fd())
    
    // 获取 socket 文件描述符
    connFile, err := conn.File()
    if err != nil {
        return err
    }
    defer connFile.Close()
    sockfd := int(connFile.Fd())
    
    // 使用 sendfile 系统调用实现零拷贝
    var offset int64 = 0
    remaining := fileInfo.Size()
    
    for remaining > 0 {
        // Linux sendfile: 从文件直接发送到 socket
        n, err := syscall.Sendfile(sockfd, filefd, &offset, int(remaining))
        if err != nil {
            return err
        }
        remaining -= int64(n)
    }
    
    return nil
}

零拷贝原理

  • 传统方式:文件 → 内核缓冲区 → 用户缓冲区 → Socket缓冲区 → 网卡(4次拷贝)
  • 零拷贝:文件 → Socket缓冲区 → 网卡(2次拷贝,无用户态参与)

常见问题与优化

inode 耗尽

现象:磁盘空间充足但无法创建文件

原因:大量小文件导致 inode 用尽

查看

df -i  # 查看inode使用率

解决

  • 删除不必要的小文件
  • 重新格式化分区增加 inode 数量

磁盘 IO 性能优化

1. 使用 SSD:IOPS 和延迟优于机械硬盘

2. 合理选择 IO 模式

  • 数据库:Direct IO + AIO
  • 日志文件:标准 IO + 批量写入
  • 大文件传输:mmap 或 sendfile

3. IO 调度器选择

# 查看当前调度器
cat /sys/block/sda/queue/scheduler

# SSD 推荐 noop 或 deadline
echo noop > /sys/block/sda/queue/scheduler

# 机械硬盘推荐 cfq(默认)

文件描述符限制

查看当前限制

ulimit -n  # 当前shell的限制
cat /proc/sys/fs/file-max  # 系统级限制

调整限制

# 临时修改
ulimit -n 65535

# 永久修改 /etc/security/limits.conf
* soft nofile 65535
* hard nofile 65535

生产环境建议

  • Web服务器:65535
  • 数据库:100000+

本章小结

文件系统是操作系统管理存储资源的核心组件,理解VFS、inode、页缓存等概念对于优化IO性能至关重要。

关键要点

  • ✅ VFS提供统一的文件操作接口
  • ✅ inode存储文件元数据,与文件名分离
  • ✅ 页缓存可显著提升IO性能
  • ✅ 零拷贝技术减少数据拷贝次数

扩展阅读


💡 思考题

  1. VFS的作用是什么?为什么需要它?
  2. inode耗尽和磁盘空间耗尽有什么区别?
  3. 什么场景下应该使用Direct IO?

⏮️ 上一节:内存管理 | ⏭️ 下一节:网络IO