在linux操作系统中,我们最常见的文本,图片,可执行二进制文件这些是最为常见的文件。除此之外文件夹也是一种特殊的文件,软链接、硬链接依然是文件。不仅如此,就连我们/dev下面的硬件设备、套接字、管道这些东西在Linux中统统都是文件。
索引节点和目录项
Linux中所有文件都有一个唯一与之对应的索引节点(Index Node),索引节点记录了文件的元数据,操作系统并不通过文件名,而是通过索引节点来管理文件,用目录项(Directory Entry)来描述文件之间的关系。
-
索引节点,简称为 inode,用来记录文件的元数据,比如 inode 编号、文件大小、访问权限、修改日期、数据的位置等。索引节点和文件一一对应,它跟文件内容一样,都会被持久化存储到磁盘中。所以记住,索引节点同样占用磁盘空间。
-
目录项,简称为 dentry,用来记录文件的名字、索引节点指针以及与其他目录项的关联关系。多个关联的目录项,就构成了文件系统的目录结构。不过,不同于索引节点,目录项是由内核维护的一个内存数据结构,所以通常也被叫做目录项缓存。
简言之,索引节点相当于文件的指针,目录项维护着文件的树型关系。
磁盘的存储区域
-
扇区:磁盘最小读写单位为扇区,每个扇区大小为512B
-
逻辑块:如果操作系统以最小单位读写磁盘,效率无疑是非常底下的,因此将8个连续扇区组成一个4k大小的逻辑块作为数据单元来进行管理
在进行文件系统格式化时,会将磁盘划分为三个区域:
-
超级块,存储整个文件系统的状态。
-
索引节点区,用来存储索引节点。
-
数据块区,则用来存储文件数据。
磁盘、索引节点、目录项、逻辑块的关系如下图所示:
目录项本身是一个内存缓存,索引节点则是存储在磁盘中,但是为了加快文件访问速度,索引节点和文件内容也会被读入到缓存中。
虚拟文件系统
索引节点、目录项、逻辑块、超级块是构成文件系统的四大基本要素。但是,为了能够使用各种不同的文件系统,在用户进程和内核之间引入了一个抽象层——虚拟文件系统VFS。
VFS定义了一组所有文件系统都支持的数据结构和标准接口。因此用户进程只需要和VFS交互即可,无需针对每一种文件系统开发不同的应用程序。
文件系统按照存储位置不同,可分为三类:
-
基于磁盘的文件系统:Ext4、XFS、OverlayFS 等, 直接将数据存储在本地挂在的磁盘。
-
基于内存的文件系统:如/proc、/sys等目录,无需分配磁盘空间,但是占用内存。
-
网络文件系统:访问远程其他主机的文件系统,如NTFS、SMB等。
文件系统的IO类型
根据文件系统的读写差异,可以将IO分为四种类型:
-
缓冲 I/O,是指利用标准库缓存来加速文件的访问,而标准库内部再通过系统调度访问文件。
-
非缓冲 I/O,是指直接通过系统调用来访问文件,不再经过标准库缓存。
此处标准库缓存指的是利用栈、队列等一些数据结构进行的资源调度,而不是页缓存。无论是否缓冲IO,都会通过系统调用页缓存来减少IO次数。
根据是否利用操作系统的页缓存,可以把文件 I/O 分为直接 I/O 与非直接 I/O。
-
直接 I/O,是指跳过操作系统的页缓存,直接跟文件系统交互来访问文件。
-
非直接 I/O 正好相反,文件读写时,先要经过系统的页缓存,然后再由内核或额外的系统调用,真正写入磁盘。
通常情况下我们的IO都是非直接IO,在数据库等场景中,你还会看到,跳过文件系统读写磁盘的情况,也就是我们通常所说的裸 I/O。
据应用程序是否阻塞自身运行,可以把文件 I/O 分为阻塞 I/O 和非阻塞 I/O:
-
所谓阻塞 I/O,是指应用程序执行 I/O 操作后,如果没有获得响应,就会阻塞当前线程,自然就不能执行其他任务。
-
所谓非阻塞 I/O,是指应用程序执行 I/O 操作后,不会阻塞当前的线程,可以继续执行其他的任务,随后再通过轮询或者事件通知的形式,获取调用的结果。
默认情况下IO都是阻塞的。网络编程中非阻塞 I/O,通常会跟 select/poll 配合,用在网络套接字的 I/O 中。
根据是否等待响应结果,可以把文件 I/O 分为同步和异步 I/O:
-
所谓同步 I/O,是指应用程序执行 I/O 操作后,要一直等到整个 I/O 完成后,才能获得 I/O 响应。
-
所谓异步 I/O,是指应用程序执行 I/O 操作后,不用等待完成和完成后的响应,而是继续执行就可以。等到这次 I/O 完成后,响应会用事件通知的方式,告诉应用程序。
文件系统的观测
-
容量:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
jeeyshe@jeeyshe-PC:~$ df 文件系统 1K-块 已用 可用 已用% 挂载点 udev 3997588 0 3997588 0% /dev tmpfs 805208 1868 803340 1% /run /dev/sda3 46631732 8521096 35712124 20% / tmpfs 4026032 44240 3981792 2% /dev/shm tmpfs 5120 4 5116 1% /run/lock tmpfs 4026032 0 4026032 0% /sys/fs/cgroup /dev/sda1 306584 6668 299916 3% /boot/efi /dev/sda4 93266544 8084300 80401548 10% /home tmpfs 805204 40 805164 1% /run/user/1000 /dev/sda5 93266544 57368 88428480 1% /media/jeeyshe/_dde_data /dev/sdb3 115272700 45983312 69289388 40% /media/jeeyshe/500CEF460CEF25A6 |
索引节点的容量,(也就是 Inode 个数)是在格式化磁盘时设定好的,一般由格式化工具自动生成。当你发现索引节点空间不足,但磁盘空间充足时,很可能就是过多小文件导致的。
加入一下参数可以看到更加详细和人性化的容量信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
jeeyshe@jeeyshe-PC:~$ df -ih 文件系统 Inode 已用(I) 可用(I) 已用(I)% 挂载点 udev 976K 576 976K 1% /dev tmpfs 983K 890 983K 1% /run /dev/sda3 2.9M 239K 2.7M 9% / tmpfs 983K 46 983K 1% /dev/shm tmpfs 983K 7 983K 1% /run/lock tmpfs 983K 17 983K 1% /sys/fs/cgroup /dev/sda1 0 0 0 - /boot/efi /dev/sda4 5.7M 98K 5.6M 2% /home tmpfs 983K 28 983K 1% /run/user/1000 /dev/sda5 5.7M 11 5.7M 1% /media/jeeyshe/_dde_data /dev/sdb3 67M 503K 67M 1% /media/jeeyshe/500CEF460CEF25A6 |
-
缓存:此处只观测索引节点和目录项
关于页缓存、swap、buf等概念,将在其他篇章介绍。