文件系统其实是操作系统中存储的核心、计算、网络。除了使用寄存器、内存可以临时存储数据,使用磁盘持久化存储更重要。
- 磁盘为系统提供了数据持久化功能。
- 文件系统在磁盘的基础上,抽象出了一个管理文件的树状结构
索引节点和目录项
Linux中一切皆是文件,linunx为每个文件都分配了两个数据结构,索引节点(index node)和目录项 (directory entry)。记录文件的元信息和目录结构。
- 索引节点:记录文件的元数据,主要包含文件大小、访问权限、修改日期、数据位置等。一个文件就对应一个索引节点。同样会被存储在磁盘中,占用磁盘空间。
- 目录项:记录文件的名字、索引节点指针和其他目录项的关联关系。多个关联的目录项就构成了文件系统的目录结构。目录项是内核维护的内存数据结构,也叫目录项缓存。
索引节点是每个文件的唯一标识,而目录项维护的是文件系统的树状结构。说白了就是索引节点是对于文件来说的,目录项是对于文件系统来说的。对应关系就是一个索引节点对应多个目录项。比如通过软连接的方式,其实都指向同一个文件,只不过不同的目录,但是目录项都需要进行维护。前者是记录文件的元数据,后者是记录文件间的目录结构。
到这里就有一个问题,那就是文件的数据是如何存储的?
磁盘读写的最小单位是扇区,扇区只有512B,所以通过文件系统将多个连续的扇区组织成一个逻辑块。以逻辑块进行操作,常见的就是4KB。
目录项本身是一个内存缓存,而索引节点是存储在磁盘中的数据。为了提供读写速度,文件内容也会缓存在页缓存cache中。索引节点也会缓存到内存中,加速文件的访问。
磁盘在进行系统格式化时,分为三个存储区域 超级块,索引节点区和数据块区
- 超级块:存储整个文件系统的状态
- 索引节点区:存储索引节点
- 数据块区:存储文件数据
虚拟文件系统
在平时的操作中,会有各种不同的数据文件格式,所以linux在用户进程和文件系统中间,引入了一层虚拟文件系统(virtual file system)
应用程序通过操作系统调用的时候就只需要操作虚拟文件系统就可以。VFS屏蔽了底层的细节。
而常见的三种文件系统大地如下:基本本机的磁盘、本机内存、远程的服务器的磁盘。
文件系统IO
将文件系统挂载到挂载点后,就可以通过挂载点进行操作文件了。vfs提供了一套标准化的接口供应用程序调用。
常见的IO分类如下
- 缓冲与非缓冲IO (在于是否使用标准库缓存)
- 直接和非直接IO (在于是否利用页缓存)
- 阻塞与非阻塞IO (当前线程是否阻塞)
- 同步与异步IO (是否等待响应结果)
Linux 一切皆文件”的深刻含义。无论是普通文件和块设备、还是网络套接字和管道等,它们都通过统一的 VFS 接口来访问。
性能观测
缓存
free 输出的cache是页缓存和可回收slab缓存的和。
root@qxlxi:/data# free -h
total used free shared buff/cache available
Mem: 3.8Gi 1.1Gi 211Mi 1.1Gi 2.5Gi 1.4Gi
Swap: 1.9Gi 833Mi 1.1Gi
root@qxlxi:/data# cat /proc/meminfo | grep -E "SReclaimable|Cached"
Cached: 2388384 kB
SwapCached: 2888 kB
SReclaimable: 124936 kB
目录和各个文件系统索引节点的缓存情况
cat /proc/slabinfo | grep -E '^#|dentry|inode'
slabtop ,来找到占用内存最多的缓存类型。
root@qxlxi:/data# slabtop
Active / Total Objects (% used) : 834715 / 923987 (90.3%)
Active / Total Slabs (% used) : 33235 / 33235 (100.0%)
Active / Total Caches (% used) : 95 / 139 (68.3%)
Active / Total Size (% used) : 187562.83K / 214143.63K (87.6%)
Minimum / Average / Maximum Object : 0.02K / 0.23K / 8.00K
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
249756 232736 93% 0.10K 6404 39 25616K buffer_head
105960 99588 93% 0.13K 3532 30 14128K kernfs_node_cache
105315 74999 71% 0.19K 5015 21 20060K dentry
86848 82365 94% 0.12K 2714 32 10856K kmalloc-128
46987 45635 97% 0.20K 2473 19 9892K vm_area_struct
43712 41460 94% 0.06K 683 64 2732K anon_vma_chain
33379 25805 77% 1.07K 1151 29 36832K ext4_inode_cache
29631 22854 77% 0.57K 2119 14 16952K radix_tree_node
23584 21053 89% 0.12K 737 32 2948K kmalloc-rcl-128
23322 22669 97% 0.09K 507 46 2028K anon_vma
21760 18704 85% 0.25K 1360 16 5440K filp
21476 20469 95% 0.59K 1652 13 13216K inode_cache
16218 14656 90% 0.04K 159 102 636K ext4_extent_status
11900 11621 97% 0.02K 70 170 280K numa_policy
8704 8213 94% 0.06K 136 64 544K vmap_area
7764 7317 94% 0.66K 647 12 5176K proc_inode_cache
6272 6242 99% 0.12K 196 32 784K pid
5202 5152 99% 0.08K 102 51 408K task_delay_info
4816 4745 98% 0.50K 301 16 2408K kmalloc-512
4590 4590 100% 0.05K 54 85 216K ftrace_event_field
4200 4149 98% 0.19K 200 21 800K cred_jar
4182 4182 100% 0.04K 41 102 164K pde_opener
3760 3660 97% 0.25K 235 16 940K kmalloc-256
3728 3178 85% 1.00K 233 16 3728K kmalloc-1k
3366 2652 78% 0.70K 153 22 2448K shmem_inode_cache
3344 3083 92% 0.81K 176 19 2816K sock_inode_cache
3248 3188 98% 0.25K 203 16 812K skbuff_head_cache
3080 3080 100% 0.07K 55 56 220K eventpoll_pwq
2568 2473 96% 4.00K 321 8 10272K kmalloc-4k
2368 2368 100% 0.06K 37 64 148K ext4_io_end
2320 2278 98% 1.00K 145 16 2320K PING
2080 2043 98% 0.12K 65 32 260K kmem_cache_node
2064 1941 94% 0.50K 129 16 1032K kmem_cache
1932 1932 100% 0.09K 42 46 168K trace_event_file
小结
本篇 我们介绍了文件系统中比较重要的概念,索引节点和目录项。一个是存储数据的元数据,另一个是为了文件系统的服务。进而为了将多个不同的文件格式统一,抽象除了VFS。 应用程序进行操作VFS就可以读写文件,接着介绍了查看索引节点和目录树缓存的方式。
而其中涉及的缓存 比如pagecache、索引节点缓存、目录树缓存本质都是为了加速读写文件的效率。