相关概念

索引节点和目录项

文件系统本身是对存储设备上的文件,进行组织管理的机制。组织方式不同,就会形成不同的文件系统。Linux系统一切皆文件。为了管理方便,Linux文件系统为每个文件都分配了链各个数据结构:索引节点(index node)和目录项(directory entry)

  • 索引节点用来记录文件的元数据,比如inode编号、文件大小、访问权限、修改日期、数据位置等。索引节点和文件一一对应,跟文件内容一样会被持久化到磁盘中
  • 目录项用来记录文件的名字、索引节点指针以及与其他目录项的关联关系。

image.png

虚拟文件系统

为了支持各种不同的文件系统,Linux内核在用户进程和文件系统的中间又引入了一个抽象层:虚拟文件系统VFS(Virtual File System)
VFS定义了一组所有文件系统都支持的数据结构和标准接口。
image.png
按照存储位置的不同,Linux支持的文件系统分为三类:

  • 基于此盘的文件系统:把数据直接存储在计算机本地挂载的磁盘中
  • 基于内存的文件系统:不需要磁盘存储空间,但是需要占用内存
  • 网络文件系统:用来访问其他计算机数据的文件系统

    文件系统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操作后,不用等待完成和完成后的响应,而是继续执行

性能观测

容量

通过df命令可以查看系统的磁盘空间使用情况

$ df Filesystem 1K-blocks Used Available Use% Mounted on /dev/sda2 55620664 15093396 37695244 29% / tmpfs 66023812 44 66023768 1% /dev/shm /dev/sda1 944792 79288 816680 9% /boot /dev/sdb1 2338229792 1856852728 481377064 80% /home /dev/sda4 117130364 64100 117066264 1% /tmp /dev/sda5 109749908 2883152 106866756 3% /var/log

使用df -f命令可以看到以1K-blocks衡量的磁盘空间使用情况

$ df -h Filesystem Size Used Avail Use% Mounted on /dev/sda2 54G 15G 36G 29% / tmpfs 63G 44K 63G 1% /dev/shm

/dev/sda1 923M 78M 798M 9% /boot

/dev/sdb1 2.2T 1.8T 459G 80% /home

/dev/sda4 112G 63M 112G 1% /tmp

/dev/sda5 105G 2.7G 103G 3% /var/log

使用 df -i可以查看索引节点的磁盘使用情况

$ df -h -i

Filesystem Inodes IUsed IFree IUse% Mounted on

/dev/sda2 3.4M 1.6M 1.8M 48% /

tmpfs 16M 12 16M 1% /dev/shm

/dev/sda1 60K 46 60K 1% /boot

/dev/sdb1 447M 16M 432M 4% /home

/dev/sda4 112M 545 112M 1% /tmp

/dev/sda5 105M 191 105M 1% /var/log

缓存

通过slabtop分析内存占用

按下 c 按照缓存大小排序,按下 a 按照活跃对象数排序

$ slabtop Active / Total Objects (% used) : 4704763 / 7113523 (66.1%)

Active / Total Slabs (% used) : 287998 / 288191 (99.9%)

Active / Total Caches (% used) : 111 / 187 (59.4%)

Active / Total Size (% used) : 873906.21K / 1153283.66K (75.8%)

Minimum / Average / Maximum Object : 0.02K / 0.16K / 4096.00K

OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME

3811962 2611268 68% 0.10K 103026 37 412104K buffer_head

435613 364391 83% 0.20K 22927 19 91708K vm_area_struct

649033 362442 55% 0.05K 8429 77 33716K anon_vma_chain

327020 236948 72% 0.19K 16351 20 65404K dentry

264810 201418 76% 0.25K 17654 15 70616K filp

213234 170934 80% 0.55K 30462 7 121848K radix_tree_node

334263 165732 49% 0.05K 4989 67 19956K anon_vma

145136 133144 91% 1.00K 36284 4 145136K xfs_inode

128435 109749 85% 0.22K 7555 17 30220K xfs_ili

411997 74024 17% 0.06K 6983 59 27932K size-64

49616 40695 82% 0.03K 443 112 1772K size-32

33291 33270 99% 0.14K 1233 27 4932K sysfs_dir_cache

18486 16557 89% 0.64K 3081 6 12324K proc_inode_cache

17066 15474 90% 0.07K 322 53 1288K Acpi-Operand

33540 10141 30% 0.12K 1118 30 4472K size-128

10860 9745 89% 0.58K 1810 6 7240K inode_cache

9896 9574 96% 1.00K 2474 4 9896K size-1024

21390 9275 43% 0.12K 713 30 2852K pid

17680 9156 51% 0.11K 520 34 2080K task_delay_info

9753 8807 90% 2.61K 3251 3 26008K task_struct

10960 8251 75% 0.19K 548 20 2192K size-192

8280 8236 99% 0.04K 90 92 360K Acpi-Namespace

12339 7809 63% 0.81K 1371 9 10968K task_xstate

10060 5977 59% 0.38K 1006 10 4024K xfs_buf

5720 5361 93% 0.50K 715 8 2860K size-512

磁盘工作原理

按照存储介质不同,磁盘可以分为机械磁盘(HDD)和固态磁盘(SSD).机械磁盘主要由盘片和读写磁头组成,数据存储在盘片的环状磁道中,在读写数据前,需要移动读写磁头,定位到数据所在磁道,才能访问数据。固态磁盘由固态电子元器件组成,固态磁盘不需要磁道寻址,所以不管是练习I/O还是随机I/O,都比机械磁盘性能好

通用块层

通用块层是处在文件系统和磁盘驱动中间的一个块设备抽象层。Linux系统通过统一的通用块层管理各种不同的块设备。主要有两个功能:

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

    I/O栈

    image.png

  • 文件系统层,包括虚拟文件系统和其他各种文件系统的具体实现。它为上层的应用程序,提供标准的文件访问接口;对下会通过通用块层,来存储和管理磁盘数据。

  • 通用块层,包括块设备 I/O 队列和 I/O 调度器。它会对文件系统的 I/O 请求进行排队,再通过重新排序和请求合并,然后才要发送给下一级的设备层。
  • 设备层,包括存储设备和相应的驱动程序,负责最终物理设备的 I/O 操作

磁盘性能指标

只要有使用率、饱和度、IOPS、吞吐量以及响应时间5个指标

  • 使用率,是指磁盘处理 I/O 的时间百分比。过高的使用率(比如超过 80%),通常意味着磁盘 I/O 存在性能瓶颈。
  • 饱和度,是指磁盘处理 I/O 的繁忙程度。过高的饱和度,意味着磁盘存在严重的性能瓶颈。当饱和度为 100% 时,磁盘无法接受新的 I/O 请求。
  • IOPS(Input/Output Per Second),是指每秒的 I/O 请求数。
  • 吞吐量,是指每秒的 I/O 请求大小。
  • 响应时间,是指 I/O 请求从发出到收到响应的间隔时间

    磁盘IO观测

通过iostat命令可以观测磁盘I/O性能

$ iostat -d -x 1

Linux 2.6.32-573.18.1.el6.toav2.x8664 () 2020年06月21日 _x86_64 (48 CPU)

Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util

sda 0.42 4.13 1.00 3.18 39.20 224.61 63.17 0.01 2.41 0.58 0.24

sdb 0.90 1.08 102.75 38.95 17413.37 5162.92 159.33 0.09 0.64 0.46 6.59

  • rrqm/s指每条合并的读请求数
  • wrqm/s指每秒合并的写请求数
  • r/s 指每秒发送给磁盘的读请求数
  • w/s指每秒发送给磁盘的写请求数
  • rkB/s指每秒从磁盘读取的数据量,单位为kb
  • wkB/s指每秒向磁盘写入的数据量,单位为kb

    进程I/O观测

    通过pidstat -d观测

    $ pidstat -d 1

Linux 2.6.32-573.18.1.el6.toav2.x8664 () 2020年06月21日 _x86_64 (48 CPU)

13时13分24秒 PID kB_rd/s kB_wr/s kB_ccwr/s Command

13时13分25秒 14044 0.00 3.54 0.00 nginx

13时13分25秒 14056 0.00 7.08 0.00 nginx

13时13分25秒 14058 0.00 3.54 0.00 nginx

13时13分25秒 14059 0.00 3.54 0.00 nginx

13时13分25秒 14063 0.00 7.08 0.00 nginx

13时13分25秒 14066 0.00 10.62 0.00 nginx

13时13分25秒 14068 0.00 7.08 0.00 nginx

13时13分25秒 14073 0.00 7.08 0.00 nginx

13时13分25秒 14078 0.00 3.54 0.00 nginx

13时13分25秒 14083 0.00 3.54 0.00 nginx

13时13分25秒 14086 0.00 10.62 0.00 nginx

13时13分25秒 16434 0.00 3.54 0.00 python

13时13分25秒 21117 0.00 14.16 0.00 python

13时13分25秒 33828 0.00 3.54 0.00 python

13时13分25秒 40949 0.00 7.08 0.00 ruby

13时13分25秒 43321 0.00 3.54 0.00 gunicorn_task_i

13时13分25秒 43666 0.00 3.54 0.00 supervisord

13时13分25秒 43668 0.00 3.54 0.00 task_schedule_w