0%

Linux文件系统与磁盘IO

文件系统是对存储设备上的文件进行组织管理的机制。Linux文件系统在磁盘的基础上管理文件的树状结构。为了方便管理,Linux文件系统为每个文件都分配了两个数据结构,索引节点(index node)和目录项(directory entry)。

目录项、超级块、索引节点、数据块共同组成了Linux文件系统的四大基本要素。

  • 目录项(目录项缓存):内核维护的内存数据结构,记录文件的名字、索引节点指针及与其他目录项的关联关系。多个关联的目录项构成了文件系统的目录结构
  • 超级块:存储整个文件系统的状态
  • 索引节点:记录文件元数据(inode编号、文件大小、访问权限、修改日期、数据位置等),与文件一一对应。
  • 数据块:存储文件数据

内核使用Slab机制管理目录项和索引节点缓存,Slab分配的内存在/proc/meminfo中记录为:

  • SReclaimable:slab中可回收的部分;
  • SUnreclaim:slab中不可回收的部分;
  • Slab:slab中所有的内存,上面两者之和;

可通过/proc/slabinfo文件查看所有目录项缓存和索引节点缓存:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# cat /proc/slabinfo | grep -E '^#|dentry|inode'
# name <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>
btrfs_inode 0 0 1136 14 4 : tunables 0 0 0 : slabdata 0 0 0
ufs_inode_cache 0 0 808 10 2 : tunables 0 0 0 : slabdata 0 0 0
qnx4_inode_cache 0 0 680 12 2 : tunables 0 0 0 : slabdata 0 0 0
hfs_inode_cache 0 0 832 19 4 : tunables 0 0 0 : slabdata 0 0 0
minix_inode_cache 0 0 672 12 2 : tunables 0 0 0 : slabdata 0 0 0
ntfs_big_inode_cache 0 0 960 8 2 : tunables 0 0 0 : slabdata 0 0 0
ntfs_inode_cache 0 0 296 13 1 : tunables 0 0 0 : slabdata 0 0 0
xfs_inode 0 0 960 8 2 : tunables 0 0 0 : slabdata 0 0 0
ovl_inode 3381 3381 688 23 4 : tunables 0 0 0 : slabdata 147 147 0
mqueue_inode_cache 8 8 960 8 2 : tunables 0 0 0 : slabdata 1 1 0
fuse_inode 0 0 832 19 4 : tunables 0 0 0 : slabdata 0 0 0
ecryptfs_inode_cache 0 0 1024 8 2 : tunables 0 0 0 : slabdata 0 0 0
fat_inode_cache 0 0 744 11 2 : tunables 0 0 0 : slabdata 0 0 0
squashfs_inode_cache 1452 1452 704 11 2 : tunables 0 0 0 : slabdata 132 132 0
ext4_inode_cache 12629 16875 1088 15 4 : tunables 0 0 0 : slabdata 1125 1125 0
hugetlbfs_inode_cache 13 13 624 13 2 : tunables 0 0 0 : slabdata 1 1 0
sock_inode_cache 564 583 704 11 2 : tunables 0 0 0 : slabdata 53 53 0
shmem_inode_cache 4134 4719 712 11 2 : tunables 0 0 0 : slabdata 429 429 0
proc_inode_cache 3968 3996 680 12 2 : tunables 0 0 0 : slabdata 333 333 0
inode_cache 17162 17459 608 13 2 : tunables 0 0 0 : slabdata 1343 1343 0
dentry 40459 51051 192 21 1 : tunables 0 0 0 : slabdata 2431 2431 0

可使用slabtop命令来找到占用slab内存最多的缓存类型。

虚拟文件系统VFS

虚拟文件系统(Virtual File Ssystem)是Linux内核在用户进程与文件系统中间引入的一个抽象层。VFS定义了一组所有文件系统都支持的数据结构和标准接口。

io.jpg

文件系统I/O分类

VFS提供了一组标准文件访问接口,这些接口以系统调用的方式供给应用程序使用。文件读写方式的差异,导致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操作完成,才会响应。如在操作文件时,设置了O_SYNC(文件数据、文件元数据写入磁盘)或O_DSYNC(文件数据写入磁盘)标志。
  • 异步I/O:在内核角度,应用程序发出I/O请求后,无需等待I/O操作完成。I/O操作完成后,响应以事件通知的方式,告诉应用程序。如在访问管道或网络套接字时,设置了O_ASYNC标志。

通用块层

为减少不同块设备的差异,linux通过一个统一的通用块层来管理不同的块设备。通用块层是处于文件系统与磁盘驱动之间的设备抽象层。

通用块层向上为文件系统和应用程序,提供访问块设备的标准接口;向下,把各种异构的磁盘设备抽象为统一的块设备,提供统一框架来管理这些设备的驱动程序。

通用块层还会给文件系统和应用程序发来的I/O请求排队,通过重新排序、请求合并等方式,提供磁盘读写效率。I/O请求排序的不同,产生了不同的I/O调度算法

  • None:常用在虚拟机中,磁盘I/O调度交给物理机负责;
  • NOOP:先入先出队列,并做简单的请求合并,常用语SSD磁盘;
  • CFQ:完全公平调度,很多linux发行版的默认调度策略,为每个进程维护一个I/O调度队列,按照时间片均匀分布每个进程的I/O请求。另外,其还支持进程I/O优先级调度。适用于大量进程的场景;
  • DeadLine:分别为读、写请求创建不同的I/O队列,确保达到最终期限的请求被有限处理,适用于I/O压力比较重的场景,如数据库等。

磁盘性能指标

磁盘性能常见指标:

  • 使用率:磁盘处理I/O的时间百分比;
  • 饱和度:磁盘处理I/O的繁忙程度,当饱和度100%时,磁盘无法接收新I/O请求(无法直接测量,需根据请求队列长度和等待时间对比评估);
  • IOPS(Input/Output Per Second):每秒I/O请求数(读请求+写请求)
  • 吞吐量:每秒I/O请求大小(读写相加);
  • 响应时间:I/O请求从发出到收到响应的间隔时间;

不同场景中,对磁盘性能指标的侧重点不同。如数据库、小文件场景,更关注的是IOPS;对多媒体等顺序读写较多的场景中,更关注吞吐量。

磁盘性能测试

fio

linux系统下一般使用fio命令进行磁盘性能测试,常用参数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
filename=/dev/emcpowerb 支持文件系统或者裸设备,-filename=/dev/sda2或-filename=/dev/sdb
direct=1 测试过程绕过机器自带的buffer,使测试结果更真实
rw=randwread 测试随机读的I/O
rw=randwrite 测试随机写的I/O
rw=randrw 测试随机混合写和读的I/O
rw=read 测试顺序读的I/O
rw=write 测试顺序写的I/O
rw=rw 测试顺序混合写和读的I/O
bs=4k 单次io的块文件大小为4k
bsrange=512-2048 同上,提定数据块的大小范围
size=5g 本次的测试文件大小为5g,以每次4k的io进行测试
numjobs=30 本次的测试线程为30
runtime=1000 测试时间为1000秒,如果不写则按照bs定义大小知道写满size大小为止
ioengine=psync io引擎使用psync方式,如果要使用libaio引擎,需要yum install libaio-devel包
rwmixwrite=30 在混合读写的模式下,写占30%
group_reporting 关于显示结果的,汇总每个进程的信息
此外
lockmem=1g 只使用1g内存进行测试
zero_buffers 用0初始化系统buffer
nrfiles=8 每个进程生成文件的数量

fio常用命令组合:

100%随机,100%读, 4K

1
fio -filename=/dev/emcpowerb -direct=1 -iodepth 1 -thread -rw=randread -ioengine=psync -bs=4k -size=1000G -numjobs=50 -runtime=180 -group_reporting -name=rand_100read_4k

100%随机,100%写, 4K

1
fio -filename=/dev/emcpowerb -direct=1 -iodepth 1 -thread -rw=randwrite -ioengine=psync -bs=4k -size=1000G -numjobs=50 -runtime=180 -group_reporting -name=rand_100write_4k

100%顺序,100%读 ,4K

1
fio -filename=/dev/emcpowerb -direct=1 -iodepth 1 -thread -rw=read -ioengine=psync -bs=4k -size=1000G -numjobs=50 -runtime=180 -group_reporting -name=sqe_100read_4k

100%顺序,100%写 ,4K

1
fio -filename=/dev/emcpowerb -direct=1 -iodepth 1 -thread -rw=write -ioengine=psync -bs=4k -size=1000G -numjobs=50 -runtime=180 -group_reporting -name=sqe_100write_4k

100%随机,70%读,30%写 4K

1
fio -filename=/dev/emcpowerb -direct=1 -iodepth 1 -thread -rw=randrw -rwmixread=70 -ioengine=psync -bs=4k -size=1000G -numjobs=50 -runtime=180 -group_reporting -name=randrw_70read_4k

I/O性能测试需要考虑不同文件大小、目录层级深度的情况。

测试结果含义:

slat:从I/O提交到实际执行I/O的时长;

clat:从I/O提交到I/O完成的时长;

lat:从创建I/O到完成的总时长;

bw:吞吐量

对于同步I/O,clat为0;对于异步I/O,lat近似于slat+clat。

blktrace

blktrace可记录磁盘的I/O访问情况,配合fio做I/O重放,可更加精确的模拟实际应用磁盘I/O情况。

1
2
3
4
5
# blktrace /dev/sdb
# ls
sdb.blktrace.0 sdb.blktrace.1
# blktrace sdb -d sdb.bin
# fio --name=replay --filename=/dev/sdb --direct=1 --read_iolog=sdb.bin

iostat

iostat查看系统整体的I/O情况。

1
2
3
4
5
6
7
8
9
10
# iostat -d -x 1
Linux 4.15.0-54-generic (blog.systemd.cn) 09/15/2019 _x86_64_ (1 CPU)

Device r/s w/s rkB/s wkB/s rrqm/s wrqm/s %rrqm %wrqm r_await w_await aqu-sz rareq-sz wareq-sz svctm %util
loop0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.13 0.00 0.00 1.11 0.00 0.02 0.00
vda 2.54 1.54 86.25 15.96 0.16 0.90 5.98 36.91 3.66 2.28 0.01 33.95 10.37 0.37 0.15

Device r/s w/s rkB/s wkB/s rrqm/s wrqm/s %rrqm %wrqm r_await w_await aqu-sz rareq-sz wareq-sz svctm %util
loop0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
vda 38.61 0.00 158.42 0.00 0.00 0.00 0.00 0.00 17.44 0.00 0.63 4.10 0.00 0.51 1.98

-d展示磁盘信息,-x展示扩展信息。

r/s w/s:每秒发送给磁盘的读写请求数(合并后)

rkB/s wkB/s:每秒从磁盘读写的数据量(kB)

rrqm/s wrqm/s:每秒合并的读写请求数

%rrqm/s %wrqm/s:每秒合并的读写请求数百分比

a_await w_await:读写请求处理等待时间(包括队列中的等待时间和设备实际处理时间,ms)

aqu-szavgqu-sz:平均请求队列长度

rareq-sz wareq-sz:平均读写请求大小(kB)

svctm:处理IO请求所需的平均时间(不含等待时间,推算值,不保证完全精确)

%util:磁盘使用I/O的时间百分比,即使用率

pidstat

pidstat可用来查看进程的I/O情况。

1
2
3
4
5
6
# pidstat -d 1
Linux 4.15.0-54-generic (blog.systemd.cn) 09/15/2019 _x86_64_ (1 CPU)

Average: UID PID kB_rd/s kB_wr/s kB_ccwr/s iodelay Command
Average: 0 175 0.00 6.09 0.00 0 jbd2/vda1-8
Average: 0 11918 0.00 0.68 0.00 0 AliYunDun

kB_ccwr/s:每秒取消的写请求数据大小;

iodelay:块I/O延迟,包括等待同步块I/O和换入块I/O结束的时间,单位是时钟周期

iotop

iostop可实时观测磁盘I/O情况。


本文为《Linux性能优化实战-倪鹏飞》笔记。

fio部分参考:
https://www.cnblogs.com/raykuan/p/6914748.html

扩展阅读:
/proc/meminfo各指标含义:http://linuxperf.com/?p=142