前言

我们继续看Linux的性能指标,今天我们来聊I/O这块。说到I/O,指的是文件系统和磁盘的输入输出。同CPU、内存一样,文件系统和磁盘也是操作系统中最核心的功能。本文从文件系统和磁盘的工作原理出发,理解Linux I/O的性能指标。

Linux文件系统与磁盘是怎么工作的

磁盘为操作系统提供了最基本的持久化存储,而文件系统则在磁盘的基础上,提供了一个用来管理文件的树状结构。
我们平时说的文件,指的是文件系统上的文件,当写文件时,先经过文件系统,再持久化到磁盘中。
而对于磁盘来说,作用范围不止于文件系统,磁盘本身是一个块设备文件,操作系统能够直接读写块设备文件,这时就不会经过文件系统。
接下来我们分别来看两者的工作方式。

文件系统如何工作

文件系统是对存储设备上的文件,进行组织管理的机制,组织方式不同,就回形成不同的文件系统,如ext4、xfs等文件系统。

管理范围

在Linux中一切皆文件,文件系统的管理范围就包括

  • 普通文件和目录
  • 块设备,如磁盘、U盘、SD卡
  • 套接字,即socket,进程间通信机制,如网络调用中以socket方式请求
  • 管道,进程间通信方式

管理的数据结构

为了方便管理,Linux文件系统为每个文件都分配两个数据结构,索引节点(index node)和目录项(directory entry 简称dentry)

  • 索引节点,简称inode,用来记录文件元数据,比如inode编号、文件大小、访问权限等。索引节点和文件一一对应,它会跟文件内容一样,会被持久化存储到磁盘中,所以索引节点同样占用磁盘空间
  • 目录项,用来记录文件的名字、索引节点指针以及与其它目录项的关联关系。多个关联的目录项,就构成了文件系统的目录结构。不同于索引节点,目录项是由内核维护的一个内存数据结构,通常也被叫做目录项缓存。

文件系统存储形式

磁盘在执行文件系统格式化时,会被分成三个存储区域

  • 超级块:记录整个文件系统的状态
  • 索引节点区:用来存储索引节点
  • 数据块区:用来存储文件数据,由逻辑块组成

image.png
通过上图,可以看到目录项、索引节点、超级块、数据块、逻辑块之间的关系

虚拟文件系统

为了支持不同的文件系统,Linux内核在用户进程和文件系统的中间,又引入了一个抽象层,也就是虚拟文件系统VFS(Virtual File System)。
VFS向上定义了一组所有文件系统都支持的数据结构和标准接口。这样,用户进程和内核中的其它子系统,只需要跟VFS提供的统一接口进行交互就可以了,不需要再关心底层各种文件系统的实现细节;向下对接各种文件系统。
下文会将虚拟文件系统、文件系统、磁盘之间的关系。

磁盘如何工作

磁盘分类

磁盘是可以持久化存储的设备,对于磁盘来说由多种分类方式

根据存储介质不同,分成机械磁盘和固态磁盘

  • 机械磁盘:也称为硬盘驱动器(Hard Disk Driver,简称HDD)。机械磁盘主要由盘片和读写磁头组成,数据就存储在盘片的环状磁道中。在读写数据前,需要移动读写磁头,定位到数据所在的磁道,然后才能访问数据。基础这个工作机制,如果I/O请求刚好连续,那就只需要一次初始的磁道寻址,孜然可以获得最佳性能。但如果是随机I/O,就需要不停地移动磁头,来定位数据位置,所以读写速度就会比较慢。
  • 固态磁盘:Solid State Disk,简称SSD,由固态电子元器件组成。固态磁盘不需要磁道寻址,所以不管是连续I/O还是随机I/O,性能都要比机械磁盘好得多。

机械磁盘的的最小读写单位是扇区,一般大小为512字节;固态磁盘的最小读写单位是页,通常大小是4KB、8KB。由于512字节比较小,每次读写这么小的单位的话效率很低,所以文件系统会把连续的扇区或页组成逻辑块,然后以逻辑块作为最小单位来管理数据。常见的逻辑块大小是4KB,也就是连续8个扇区或者单独的一个页,都可以组成一个逻辑块。

根据接口分类,有IDE(Integrated Drive Electronics)、SATA(Serial ATA)等。不同的接口往往分配不同的设备名称,比如IDE设备会分配一个hd前缀的设备名,SATA设备会分配一个sd前缀的设备名。如果是多块同类型的磁盘,就会按照a、b、c等的字母顺序来编号,如/dev/sda,表示第一个SATA接口的磁盘。

根据使用方式分类,

  • 独立磁盘:最简单的,直接作为独立磁盘设备来使用。这些磁盘还可以划分为不同的逻辑分区,每个分区再用数字编号,比如常见的/dev/sda ,还可以分成两个分区/dev/sda1和/dev/sda2。
  • 冗余独立磁盘:也就是RAID(Refundant Array of Independent Disks),把多块磁盘组合成一个逻辑磁盘,从而可以提高数据访问的性能,并且增强数据存储的可靠性。
  • 网络存储集群:把磁盘组合成一个网络存储集群,再通过NFS等网络存储协议,暴露给外部使用。

通用块层

与虚拟文件系统类似,为了减小不同块设备的差异带来的影响,Linux通过一个统一的通用块层,来管理不同的块设备。通用块层,其实是处在文件系统和磁盘驱动中间的一个块设备抽象层。它主要有两个功能:

  • 第一个功能跟虚拟文件系统的功能类似。向上,为文件系统和应用程序提供访问块设备的标准接口;向下,把各种异构的磁盘设备抽象为统一的块设备,并提供统一框架来管理这些设备的驱动程序。
  • 第二个功能,通用块层还会给文件系统和应用程序发来的I/O请求排队,并通过重新排序、请求合并等方式,提高磁盘读写的效率。

Linux系统的I/O调用图

通过该图可以将我们上面讲到的虚拟文件系统、文件系统、磁盘之间的层次关系关联起来。
image.png
通过该图,还可以看出一些东西:

  • 读写文件、磁盘需要经过内核,通过系统调用来执行
  • 存储系统的I/O,通常是整个系统中最慢的一环,所以Linux通过多种缓存机制优化I/O效率。比如使用页缓存、索引节点缓存、目录项缓存,优化文件访问性能,减少对下层块设备的直接调用;优化块设备的访问效率,使用缓冲区缓存块设备的数据

I/O性能指标

简单了解完文件系统和磁盘的工作原理后,我们来看I/O性能指标,接下来涉及到的一些概念基本都可以在上面找到。

文件系统性能指标

  • 文件系统空间容量、使用量以及剩余空间
  • 索引节点容量、使用量以及剩余量:如果文件系统中存储过多的小文件,索引节点容量也是一个要关注的点
  • 缓存
    • 页缓存:对文件内容的缓存
    • 目录项缓存
    • 索引节点缓存
    • 具体文件系统缓存(如ext4的缓存)

磁盘性能指标

  • 使用率:磁盘处理I/O的时间百分比。过高的使用率(比如超过80%),通常意味着磁盘I/O一直繁忙,可能存在性能瓶颈。通过iostat可以查看该指标
  • IOPS:每秒的I/O请求数
  • 吞吐量:每秒的I/O请求大小
  • 响应时间:I/O请求从发出到收到响应的时间间隔
  • 缓冲区

使用这些性能指标时,要结合读写比例、I/O类型(随机还是连续)以及I/O的大小综合地分析。比如在数据库、大量小文件等这类随机读写比较多的场景中,IOPS更能反映系统的整体性能;而在多媒体等顺序读写较多的场景中,吞吐量才更能反映系统的整体性能。

总结

本文重点讲了Linux I/O性能指标,通过如下的脑图可以有个整体的视角 理解Linux I/O性能指标 - 图3

参考链接