linux性能优化实战学习笔记——I/O篇
说明
这篇博客用于记录学习linux性能优化实战专栏I/O篇的一些总结,巩固自己知识点的同时也能够方便以后查询。
linux文件系统
文件系统是在磁盘系统的基础上,提供了一个用来管理文件的树状结构。根据结构方式的不同,就会形成不同的文件系统。
linux中一切皆文件。不仅普通的文件和目录,就连块设备,套接字,管道等,也都要通过统一的文件系统管理。
索引节点和目录项
linux文件系统为每个文件分配两个数据结构,索引节点和目录项:
- 索引节点:inode,用来记录文件的元数据,比如inode编号、文件大小、访问权限、修改日期、数据位置等。所以节点与文件一一对应,并且会被持久化存储到磁盘中。
- 目录项:dentry,记录文件的名字、索引节点指针以及与其他目录项的关联关系。多个关联的目录项,就构成了文件系统的目录结构。目录项是由内核维护的一个内存数据结构。
目录项与索引结构的关系是多对一的关系。两者的关系可以查看下图:
该图清晰的表达了两者的关系,补充几个磁盘这边的概念:
- 超级块:存储文件系统的状态
- 索引节点区:存储索引节点
- 数据块区:存储文件数据
虚拟文件系统
为了支持各种不同的文件系统,linux内核在用户进程和文件系统中间,引入了一个抽象层,即虚拟文件系统VFS(Virtual File System)
VFS定义了所有文件系统都需要支持的数据结构和标准接口。这样接口的使用者就与真正文件系统的实现细节解耦。
下图展示的是整个linux文件系统的架构:
文件系统按照存储位置不同可以分为以下三类:
- 基于磁盘的文件系统,常见的Ext4, XFS, OverlayFS等
- 基于内存的文件系统,该类文件系统不需要磁盘存储空间,只会占用内存。linux中用到的/proc和/sys文件系统就是属于这种。
- 网络文件系统,常见的有NFS, SMB, iSSCSI等
这些文件系统要先挂在到VFS目录树中的某个子目录,然后才能被访问。
文件系统 I/O
缓冲与非缓冲I/O
- 缓冲I/O,利用标准库缓存来加速文件访问,标准库内部再通过文件系统调用访问文件
- 非缓冲I/O,直接通过系统调用来访问文件,不再经过标准库缓存
标准库在文件系统调用基础上,自己实现了一套缓存机制。例如标准库的printf或者cout函数会在遇到换行时候才真正输出。
直接与非直接I/O
- 直接I/O:跳过操作系统页缓存,直接与文件系统交互来访问文件
- 非直接I/O:文件读写时,经过系统的页缓存,来加速文件访问与写入
页缓存利用的就是内存篇中的buffer/cache缓存模块。
阻塞与非阻塞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完成后,会通过事件通知方式告诉应用程序
这个感觉跟异步I/O与非阻塞I/O有点难区分,个人基于网络编程相关理解(不知道是否对),非阻塞I/O的话,真正读取和写入还是有应用程序自己,例如epoll通知回来的时候只是告诉应用程序这个套接字能读或者能写了,应用程序自己进行都和写操作。异步I/O的话调用之后既不用管了,会在操作完成的时候通知你读或者写已经操作完成以及操作结果如何。
磁盘I/O
Linux中,磁盘是作为一个块设备来管理的,也就是以块为单位读写数据,并支持随机读写。
通用块层
与VFS类似,为了减少不同块设备差异的影响,Linux通过一个统一的通用块层来管理不同的块设备,通用块层主要有两种功能:
- 向上为文件系统和应用程序提供统一的访问块设备标准接口;向下把各种异构的磁盘设备抽象成统一的块设备,并提供统一的框架来管理这些设备驱动程序。
- 对收到的I/O请求进行排队,并通过重新排序,请求合并方式提升磁盘访问利用率
通用块层I/O调度算法:
- NONE:不进行任何操作,完全由物理机负责
- NOOP:先入先出,并做一些最基本的请求合并,常用于SSD
- CFQ:完全公平调度器,为每个进程维护一个I/O队列,并按照时间片均匀分布每个进程的I/O请求
- Deadline:读、写分别建立I/O队列,提高机械硬盘的吞吐量,并确保达到最终期限的请求被优先处理。
I/O栈
这张图包含了介绍的存储系统I/O的层级关系:
- 文件系统层:包含虚拟文件系统及其他各个文件系统的实现
- 通用块层:包含块设备I/O队列和I/O调度器
- 设备层:负责最终物理设备的I/O操作
磁盘性能指标
- 使用率:磁盘处理I/O的时间百分比(uitl)
- 饱和度:磁盘处理I/O的繁忙程度
- IOPS:每秒I/O请求数
- 吞吐量:每秒I/O请求大小
- 响应时间:I/O请求从发出到收到响应的时间间隔
每个性能指标在不同的场景下的关注度不太一样,例如处理大量小文件的场景可能关注的是IOPS,大文件的读取可能关注的是吞吐量