我们接下来的几节,主要面向的就是文件系统和磁盘的I/O性能

同CPU 内存一样,磁盘和文件系统的管理,是操作系统核心的功能

磁盘为整个系统提供了基本的持久化存储,而文件系统则是在此之上,提供了对应的管理文件的树状结构

在Linux中,万物皆文件,那么普通的文件和目录,以及设备,套接字,管道等,也是基于文件系统进行的管理

在Linux中,Linux文件系统为每个文件分配了两个数据结构,索引节点和目录项,用于记录文件的元信息和目录结构

索引节点,又名inode,记录的是文件的元数据,比如inode编号,文件大小,访问权限,修改如期,数据位置等,索引节点和文件一对一,其和文件内容一样,都会被持久化到磁盘中,所以索引节点也会占用磁盘

目录项,称为dentry,记录文件的名字,索引节点指针,和其他目录的关联关系,由内核维护的一个内存数据结构,叫做目录项缓存

索引节点是每个文件的唯一标识,维护了文件系统的树状结构,目录项和索引节点的关系是多对一,一个文件可以有多个别名

那么有了这个关联结构,文件数据到底如何存储的?是否是直接写到磁盘中就可以了?

磁盘读写的最小单位是扇区,但是扇区只有512B,不可能每次都写这么小的单位,于是将多个连续的扇区组成了逻辑块,每次以逻辑块为单位,来管理数据,常见逻辑块是4KB,8个连续的扇区组成

图片

在磁盘执行文件系统格式化的时候,分为三个存储区域,超级块,索引节点区,数据块区

超级块,存储整个文件系统的状态

索引节点区,存储索引节点

数据块区,存储文件数据

上面这三个模块,构成了Linux文件系统的四大基本要素,不过Linux还加入了一个抽象层,就是虚拟文件系统VFS,VFS定义了一组接口,让上层的用户程序以及内核进行交互,不关心底层的具体实现

基本的Linux文件系统如下

图片

在VFS下方,有着不同的文件系统,比如Ext4,XFS, NFS等

这些文件系统中,有着直接基于磁盘的文件系统,讲数据直接存储在计算机本地的磁盘中,或者是基于内存的文件系统,就是虚拟文件系统,比如/proc,最后是网络文件系统,就是访问其他计算机数据的文件系统,比如NFS,SMB,iSCSI等

不过,无论什么系统,都需要挂载到目录树的某个子目录上,然后才能访问其中的文件

将文件系统挂在完成之后,就可以通过挂载点,访问其管理的文件了,VFS提供了标准的文件访问接口,这些接口以系统调用的方式,提供给应用程序使用

比如cat,内部就是先进行调用open(),打开一个文件,然后调用read() 读取内容, 最后调用write(),将文件内容进行输出到控制台的标准输出中

文件系统和磁盘的交互,即为IO,IO的分类很多种,可以分为

缓冲和非缓冲IO

直接和非直接IO

阻塞和非阻塞IO

同步和异步IO

我们依次说这些IO的区别

第一种,缓冲IO和非缓冲IO,缓存就是利用标准库缓存来加速文件访问,非缓冲IO则是直接通过系统调用访问文件,这里的缓冲也是系统调用,不过是有一层页缓存的存在的

第二种,直接IO,直接跳过页缓存,和文件系统进行交互,非直接IO正好相反,文件读写的时候,经过系统的页缓存,才会经由内核或者额外的系统调用,写入磁盘

直接IO的操作需要在系统调用中指定O_DIRECT指标

第三种,阻塞IO和非阻塞IO,和Java中的基本一致,就是获取不到的时候是否阻塞当前线程

第四种,就是根据是否等待响应结果,分为了同步IO和异步IO

同步IO,指的是应用程序等待IO完成后才会返回,异步IO则是执行IO后立刻返回,后续结果另算

最后性能观测片段

在文件系统的观测中,常见的就是空间不足,使用df可以观察空间使用

或者配合df -h 可以更加直观的查看空间

但是有时候,我们使用df命令查看空间,发现空间有剩余,但是空间就是不足,这是为何呢?

如果只从这一节的角度来说,可能是跟索引节点有关,索引节点也是占用磁盘空间的,df -i 可以查看索引节点的使用情况

索引节点的容量,一般在格式化磁盘的时候就设定好了,由格式化工具生成,如果索引节点空间不足,磁盘空间充足,就可能是过多的小文件导致(毕竟文件有大小,但是索引文件都基本一样大)

一般来说,删除这些小文件,或者移动到索引节点充足的其他磁盘即可

最后是关于文件系统中目录项和索引节点缓存的观察

内核使用Slab,管理目录项和索引节点的缓存,通过/proc/slabinfo来进行查看

运行如下的命令,可以得到,所有目录项和各种文件系统索引节点的缓存情况

cat /proc/slabinfo |egrep “^#|dentry|inode”

图片

其中的dentry是目录项缓存,inode_cache行表示VFS索引节点缓存

其余的是不同文件类型的节点缓存数据

还有就是slabtop这个工具

可以按照缓存大小进行排序 图片

我们这次,梳理了Linux文件系统的工作原理

Linux在不同的文件系统上,抽象出了一层的虚拟文件系统

还定义了一组通用的接口和数据结构,这样其他的子系统只需要和VFS的统一接口进行交互

最后一个思考题

如果执行如下的

$ find / -name file-name

会导致缓存的升高吗?以及是什么类型的缓存升高?

find需要遍历文件系统,而遍历文件系统的时候,需要讲索引和实际的目录树关联起来,这需要在内核中维护dentry,由于find的目录是根目录,所以必然会导致大量的dentry的生成。

发表评论

邮箱地址不会被公开。 必填项已用*标注