问题:磁盘和文件系统的关系?
答:磁盘为系统提供了最基本的持久化存储。
文件系统则在磁盘的基础上,提供了一个用来管理文件的树状结构。
文件系统,本身是对存储设备上的文件,进行组织管理的机制。组织方式不同,就会形成不同的文件系统。
问题:索引节点和目录项的功能与关系?
答:Linux 文件系统为每个文件都分配两个数据结构,索引节点(index node)和目录项(directory entry)。
索引节点( inode),用来记录文件的元数据,比如 inode 编号、文件大小、访问权限、修改日期、数据的位置等。索引节点和文件一一对应,它也会被持久化存储到磁盘中,索引节点同样占用磁盘空间。
目录项( dentry),用来记录文件的名字、索引节点指针以及与其他目录项的关联关系。多个关联的目录项,就构成了文件系统的目录结构。不同于索引节点,目录项是由内核维护的一个内存数据结构,通常也被叫做目录项缓存。
索引节点是每个文件的唯一标志,目录项维护的是文件系统的树状结构。
目录项和索引节点的关系是多对一,可以简单理解为,一个文件可以有多个别名。
问题:linux中文件数据到底是怎么存储的呢?
答:磁盘读写的最小单位是扇区,每个扇区512B. 文件系统把连续的扇区组成逻辑块,每次都以逻辑块为最小单元,来管理数据。常见的逻辑块大小为4KB,也就是连续的8个扇区组成。
问题:目录项(dentry)和索引节点(inode) 分别存储在哪里?
答:dentry本身就是一个内存缓存,inode是存储在磁盘中的数据。为了加速文件访问,inode会缓存到索引节点缓存cache中。
问题:磁盘做文件系统格式化时,会被分成哪几个区域?
答:会被分成超级块区、索引节点区、数据块区。
超级块,存储整个文件系统的状态。
索引节点区,用来存储索引节点。
数据块区,则用来存储文件数据。
问题:linux文件系统的四大基本要素是什么?
答:目录项(dentry),索引节点,逻辑块(数据块),超级块。
问题:VFS存在的必要性是什么?
答:为了支持不同的文件系统,Linux 内核在用户进程和文件系统的中间,引入了抽象层——虚拟文件系统VFS。
VFS 定义了一组所有文件系统都支持的数据结构和标准接口。用户进程和内核中的其他子系统,只需要跟 VFS 提供的统一接口进行交互,不用再关心底层各种文件系统的实现细节。
问题:按照存储位置的维度,文件系统的分类?
答: 基于磁盘的文件系统。常见的 Ext4、XFS、OverlayFS 等。
基于内存的文件系统。不需要任何磁盘分配存储空间,但会占用内存。如/proc文件系统、/sys文件系统。
网络文件系统。比如 NFS、SMB、iSCSI 等。
这些文件系统,要先挂载到 VFS 目录树中的某个子目录(称为挂载点),然后才能访问其中的文件。拿第一类,也就是基于磁盘的文件系统为例,在安装系统时,要先挂载一个根目录(/),在根目录下再把其他文件系统(比如其他的磁盘分区、/proc 文件系统、/sys 文件系统、NFS 等)挂载进来。
问题:文件IO的分类?
答:缓冲与非缓冲 I/O、直接与非直接 I/O、阻塞与非阻塞 I/O、同步与异步 I/O。
问题:缓冲I/O与非缓冲I/O的区别?
答:根据是否利用标准库缓存,可以把文件 I/O 分为缓冲 I/O 与非缓冲 I/O。
缓冲 I/O,是指利用标准库缓存来加速文件的访问,而标准库内部再通过系统调度访问文件。
非缓冲 I/O,是指直接通过系统调用来访问文件,不再经过标准库缓存。
问题:直接IO与非直接I/O的区别?
答:根据是否利用操作系统的页缓存,可以把文件 I/O 分为直接 I/O 与非直接 I/O。
直接 I/O,是指跳过操作系统的页缓存,直接跟文件系统交互来访问文件。
非直接 I/O 正好相反,文件读写时,先要经过系统的页缓存,然后再由内核或额外的系统调用,真正写入磁盘。
直接 I/O、非直接 I/O,本质上还是和文件系统交互。如果是在数据库等场景中,会有跳过文件系统读写磁盘的情况,也就是我们通常所说的裸 I/O。
问题:阻塞I/O和非阻塞I/O的区别?
答:根据应用程序是否阻塞自身运行,可以把文件 I/O 分为阻塞 I/O 和非阻塞 I/O:
阻塞 I/O,是指应用程序执行 I/O 操作后,如果没有获得响应,就会阻塞当前线程,自然就不能执行其他任务。
非阻塞 I/O,是指应用程序执行 I/O 操作后,不会阻塞当前的线程,可以继续执行其他的任务,随后再通过轮询或者事件通知的形式,获取调用的结果。
问题:同步I/O与异步I/O的区别?
答:根据是否等待响应结果,可以把文件 I/O 分为同步和异步 I/O。
同步 I/O,是指应用程序执行 I/O 操作后,要一直等到整个 I/O 完成后,才能获得 I/O 响应。
异步 I/O,是指应用程序执行 I/O 操作后,不用等待完成和完成后的响应,而是继续执行就可以。等到这次 I/O 完成后,响应会用事件通知的方式,告诉应用程序。
问题:怎么观察页缓存的大小?(待解)
在前面 Cache 案例中,我已经介绍过,可以用 free 或 vmstat,来观察页缓存的大小。复习一下,free 输出的 Cache,是页缓存和可回收 Slab 缓存的和,你可以从 /proc/meminfo ,直接得到它们的大小
问题:怎么观察文件系统中的目录项和索引节点缓存?
内核使用 Slab 机制,管理目录项和索引节点的缓存。/proc/meminfo 只给出了 Slab 的整体大小,具体到每一种 Slab 缓存,还要查看 /proc/slabinfo 这个文件。比如,运行下面的命令,可以得到所有目录项和各种文件系统索引节点的缓存情况。
命令1:查看所有目录项和各种文件系统索引节点的缓存情况
$ cat /proc/slabinfo | grep -E '^#|dentry|inode'
# name <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>
xfs_inode 0 0 960 17 4 : tunables 0 0 0 : slabdata 0 0 0
...
ext4_inode_cache 32104 34590 1088 15 4 : tunables 0 0 0 : slabdata 2306 2306 0hugetlbfs_inode_cache 13 13 624 13 2 : tunables 0 0 0 : slabdata 1 1 0
sock_inode_cache 1190 1242 704 23 4 : tunables 0 0 0 : slabdata 54 54 0
shmem_inode_cache 1622 2139 712 23 4 : tunables 0 0 0 : slabdata 93 93 0
proc_inode_cache 3560 4080 680 12 2 : tunables 0 0 0 : slabdata 340 340 0
inode_cache 25172 25818 608 13 2 : tunables 0 0 0 : slabdata 1986 1986 0
dentry 76050 121296 192 21 1 : tunables 0 0 0 : slabdata 5776 5776 0
命令2:实际性能分析中常使用 slabtop ,来找到占用内存最多的缓存类型
# 按下c按照缓存大小排序,按下a按照活跃对象数排序
$ slabtop
Active / Total Objects (% used) : 277970 / 358914 (77.4%)
Active / Total Slabs (% used) : 12414 / 12414 (100.0%)
Active / Total Caches (% used) : 83 / 135 (61.5%)
Active / Total Size (% used) : 57816.88K / 73307.70K (78.9%)
Minimum / Average / Maximum Object : 0.01K / 0.20K / 22.88K
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
69804 23094 0% 0.19K 3324 21 13296K dentry
16380 15854 0% 0.59K 1260 13 10080K inode_cache
58260 55397 0% 0.13K 1942 30 7768K kernfs_node_cache
485 413 0% 5.69K 97 5 3104K task_struct
1472 1397 0% 2.00K 92 16 2944K kmalloc-2048