LINUX性能优化--IO工作原理

同 CPU、内存一样,磁盘和文件系统的管理,也是操作系统最核心的功能。
有以下两个基本功能:
1 磁盘为系统提供了最基本的持久化存储。
2 文件系统则在磁盘的基础上,提供了一个用来管理文件的树状结构。
索引节点和目录项
在LINUX操作系统中,遵循“一切皆是文件”的思想。包括文件,目录,块设备、套接字、管道等,都是通过文件系统来管理的。组织文件的方式不同,就形成了不同的文件系统。
文件系统包括了索引节点(index node)和目录项(directory entry)。它们主要用来记录文件的元信息和目录结构。
索引节点,简称为 inode,用来记录文件的元数据,比如 inode 编号、文件大小、访问权限、修改日期、数据的位置等。索引节点和文件一一对应,它跟文件内容一样,都会被持久化存储到磁盘中。所以记住,索引节点同样占用磁盘空间
目录项,简称为 dentry,用来记录文件的名字、索引节点指针以及与其他目录项的关联关系。多个关联的目录项,就构成了文件系统的目录结构。不过,不同于索引节点,目录项是由内核维护的一个内存数据结构,所以通常也被叫做目录项缓存。
索引节点是每个文件的唯一标志,而目录项维护的文件系统的树状结构。他们之间的关系是多对一,你可以简单理解为,一个文件可以有多个别名。
因为磁盘读写的最小单位是扇区,然而扇区只有 512B 大小,如果每次都读写这么小的单位,效率一定很低。所以,文件系统又把连续的扇区组成了逻辑块,然后每次都以逻辑块为最小单元,来管理数据。常见的逻辑块大小为 4KB,也就是由连续的 8 个扇区组成。
文件系统示意图:
在这里插入图片描述
需要注意的是:
第一,目录项本身就是一个内存缓存,而索引节点则是存储在磁盘中的数据。在前面的 Buffer 和 Cache 原理中,我曾经提到过,为了协调慢速磁盘与快速 CPU 的性能差异,文件内容会缓存到页缓存 Cache 中。那么,你应该想到,这些索引节点自然也会缓存到内存中,加速文件的访问。
第二,磁盘在执行文件系统格式化时,会被分成三个存储区域,超级块、索引节点区和数据块区。 超级块,存储整个文件系统的状态。
索引节点区,用来存储索引节点。
数据块区,则用来存储文件数据
一个磁盘的分区
在这里插入图片描述
1 引导块。引导块占用第0号物理块,不属于文件系统管辖;如果系统中有多个文件系统,只有跟文件系统才有引导程序放入引导块中,其余文件系统都不使用引导块。
2 超级块。文件系统的第一个块被称为超级块,这个块存放的是文件系统本身的结构信息;比如超级块记录了每个区域的大小,存放未使用磁盘的信息等。
3 i节点表。超级块是下一个部分就是i节点表,每个文件对应一个i节点,每个文件都有一些属性,如文件大小,所有者,创建时间等。这些信息存放在对应的i节点的结构中,所有的文件都具有相同大小的i节点,这些i节点组成一个i节点表,文件系统创建后,i节点的数目是有限的。所以一个文件系统能够创建的文件也是有限的。
4 文件存储区。文件系统的第3个部分是文件存储区,文件的内容保存在这里,磁盘所有的块大小都是一样,如果文件大小超过一个块的大小,则文件会存放在多个次磁盘块中。
5 进程对换区。磁盘上会开辟一块区域, 为对换区, 当内存中的进程需要扩大占用的内存空间, 而当前内存空间不足时, 则把某些不常用的进程暂时替换到对换区中, 在适用的时候又把他们换进 内存,解决内存不足和进程之间对内存的竞争问题。
虚拟文件系统
为了支持各种不同的文件系统,LINUX在用户进程和文件系统之间引入了一个抽象层,VFS。VFS 定义了一组所有文件系统都支持的数据结构和标准接口。用户进程只需要根VFS对接,而不需要处理各种文件系统的细节。
他们之间的关系如下:
在这里插入图片描述
文件系统分为3类:
第一类是基于磁盘的文件系统,也就是把数据直接存储在计算机本地挂载的磁盘中。常见的 Ext4、XFS、OverlayFS 等,都是这类文件系统。
第二类是基于内存的文件系统,也就是我们常说的虚拟文件系统。这类文件系统,不需要任何磁盘分配存储空间,但会占用内存。我们经常用到的 /proc 文件系统,其实就是一种最常见的虚拟文件系统。此外,/sys 文件系统也属于这一类,主要向用户空间导出层次化的内核对象。
第三类是网络文件系统,也就是用来访问其他计算机数据的文件系统,比如 NFS、SMB、iSCSI 等。
各种文件系统都必须要挂载到目录下,才能使用。
文件系统 I/O
文件系统挂载到目录以后,就可以使用VFS的标准接口进行文件的操作。
文学系统是有读写方式的差异,导致了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,需要你在系统调用中,指定 O_DIRECT 标志。如果没有设置过,默认的是非直接 I/O。不过要注意,直接 I/O、非直接 I/O,本质上还是和文件系统交互。如果是在数据库等场景中,你还会看到,跳过文件系统读写磁盘的情况,也就是我们通常所说的裸 I/O。
第三,根据应用程序是否阻塞自身运行,可以把文件 I/O 分为阻塞 I/O 和非阻塞 I/O:
阻塞 I/O,是指应用程序执行 I/O 操作后,如果没有获得响应,就会阻塞当前线程,自然就不能执行其他任务。
非阻塞 I/O,是指应用程序执行 I/O 操作后,不会阻塞当前的线程,可以继续执行其他的任务,随后再通过轮询或者事件通知的形式,获取调用的结果。
比方说,访问管道或者网络套接字时,设置 O_NONBLOCK 标志,就表示用非阻塞方式访问;而如果不做任何设置,默认的就是阻塞访问。
第四,根据是否等待响应结果,可以把文件 I/O 分为同步和异步 I/O:
同步 I/O,是指应用程序执行 I/O 操作后,要一直等到整个 I/O 完成后,才能获得 I/O 响应。
异步 I/O,是指应用程序执行 I/O 操作后,不用等待完成和完成后的响应,而是继续执行就可以。等到这次 I/O 完成后,响应会用事件通知的方式,告诉应用程序。
使用标志位。可以控制IO的方式:
O_SYNC 或者 O_DSYNC 标志,就代表同步 I/O
O_ASYNC 选项后,相应的 I/O 就是异步 I/O
性能观测
容量
df 命令,就能查看文件系统的磁盘空间使用情况
缓存
free 或 vmstat,来观察页缓存的大小
内核使用 Slab 机制,管理目录项和索引节点的缓存。/proc/meminfo 只给出了 Slab 的整体大小,具体到每一种 Slab 缓存,还要查看 /proc/slabinfo 这个文件。
cat /proc/slabinfo | grep -E ‘^#|dentry|inode’
slabtop ,找到占用内存最多的缓存类型

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值