首页 Linux

Linux操作系统性能之文件系统篇

2022-07-11 16:01 腾讯云开发者社区

本篇文章是性能篇的最后一篇文章,算是一个学习笔记吧,当中的例子也是从别的文章里面摘录的,主要用来讲解如何使用和查看对应的指标。这一篇主要介绍文件系统,说的更加具体点其实是磁盘这个点。

笔者还是按照:基础知识----》常用命令和工具----〉排查思路的方式进行了整理。

一、基础知识

1. 文件系统:在磁盘的基础上,提供了一个用来管理文件的树状结构,是对存储设备上的文件,进行组织管理的机制。

为了方便管理,Linux 文件系统为每个文件都分配两个数据结构,索引节点(index node)和目录项(directory entry)。它们主要用来记录文件的元信息和目录结构,索引节点是每个文件的唯一标志,而目录项维护的正是文件系统的树状结构。目录项和索引节点的关系是多对一,你可以简单理解为,一个文件可以有多个别名。

索引节点:简称为 inode,用来记录文件的元数据,比如 inode 编号、文件大小、访问权限、修改日期、数据的位置等。索引节点和文件一一对应,它跟文件内容一样,都会被持久化存储到磁盘中。所以记住,索引节点同样占用磁盘空间。

目录项:简称为 dentry,用来记录文件的名字、索引节点指针以及与其他目录项的关联关系。多个关联的目录项,就构成了文件系统的目录结构。不过,不同于索引节点,目录项是由内核维护的一个内存数据结构,所以通常也被叫做目录项缓存。

2076e06d15149dfc5517892120ef4ae8

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

992eb1c111fd714dd0d36835733fa0ea

3. 文件系统I/O: VFS 提供了一组标准的文件访问接口,这些接口以系统调用的方式,提供给应用程序使用,例如:open()、read()、write(),可以分为下面四类。

一类,是否利用标准库缓存,可以把文件 I/O 分为缓冲 I/O 与非缓冲 I/O。

1. 缓冲 I/O,是指利用标准库缓存来加速文件的访问,而标准库内部再通过系统调度访问文件。

2. 非缓冲 I/O,是指直接通过系统调用来访问文件,不再经过标准库缓存。

二类,是否利用操作系统的页缓存,可以把文件 I/O 分为直接 I/O 与非直接 I/O。

1. 直接 I/O,是指跳过操作系统的页缓存,直接跟文件系统交互来访问文件,通常系统调用中,指定 O_DIRECT 标志。

2. 非直接 I/O 正好相反,文件读写时,先要经过系统的页缓存,然后再由内核或额外的系统调用,真正写入磁盘。

三类,应用程序是否阻塞自身运行,可以把文件 I/O 分为阻塞 I/O 和非阻塞 I/O

1. 阻塞 I/O,是指应用程序执行 I/O 操作后,如果没有获得响应,就会阻塞当前线程,自然就不能执行其他任务。

2. 非阻塞 I/O,是指应用程序执行 I/O 操作后,不会阻塞当前的线程,可以继续执行其他的任务,随后再通过轮询或者事件通知的形式,获取调用的结果。

四类,是否等待响应结果,可以把文件 I/O 分为同步和异步 I/O:

1. 同步 I/O,是指应用程序执行 I/O 操作后,要一直等到整个 I/O 完成后,才能获得 I/O 响应。

2. 异步 I/O,是指应用程序执行 I/O 操作后,不用等待完成和完成后的响应,而是继续执行就可以。等到这次 I/O 完成后,响应会用事件通知的方式,告诉应用程序。

4. 磁盘的性能指标:

1. 使用率:是指磁盘处理 I/O 的时间百分比。过高的使用率(比如超过 80%),通常意味着磁盘 I/O 存在性能瓶颈。

2. 饱和度:是指磁盘处理 I/O 的繁忙程度。过高的饱和度,意味着磁盘存在严重的性能瓶颈。当饱和度为 100% 时,磁盘无法接受新的 I/O 请求。

3. IOPS(Input/Output Per Second):是指每秒的 I/O 请求数。

4. 吞吐量:是指每秒的 I/O 请求大小。5. 响应时间:是指 I/O 请求从发出到收到响应的间隔时间。

a9be02a60870eb9b187f6fb7bf8bbe18

二、常用命令和工具

1.df // 查看磁盘空间

# -h 更好的可读性,查看/dev/sda1使用的磁盘空间

$ df -h /dev/sda1

Filesystem  Size  Used  Avail  Use%  Mounted on

/dev/sda1  29G  3.1G  26G   11%     /

# -i,查看索引节点的磁盘空间

$ df -i /dev/sda1

Filesystem  Inodes     IUsed      IFree      IUse% Mounted on

/dev/sda1  3870720  157460   3713260  5%       /

2.缓存大小查看

内核使用 Slab 机制,管理目录项和索引节点的缓存,/proc/meminfo 只给出了 Slab 的整体大小,具体到每一种 Slab 缓存,还要查看 /proc/slabinfo 这个文件。

# 查看Slab的整体大小

$ cat /proc/meminfo | grep -E "SReclaimable|Cached"

Cached: 748316 kB

SwapCached: 0 kB

SReclaimable: 179508 kB

# 查看每一种 Slab的缓存大小

$ cat /proc/slabinfo | grep -E '^#|dentry|inode'

1

# 查看缓存类型的使用大小

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

$ slabtop

2

3. iostat // 查看io的指标

# r/s:每秒发送给磁盘的读请求数

# w/s:每秒发送给磁盘的写请求数

# rkB/s:每秒从磁盘读取的数据量

# wkB/s:每秒向磁盘写入的数据量

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

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

# r_await: 读请求处理完成等待时间,包括:队列中等待时间+设备处理的时间,单位毫秒

# w_await: 写请求处理完成等待时间,包括:队列中等待时间+设备处理的时间,单位毫秒

# aqu-sz:平均请求队列长度# rareq-sz:平均读请求大小,单位KB

# wareq-sz:平均写请求大小,单位KB

# svctm:处理I/O请求所需要的平均时间,不包括等待时间,单位毫秒

# %util:磁盘处理I/O时间的百分比

# -d -x表示显示所有磁盘I/O的指标

# 备注:-d 选项是指显示出 I/O 的性能指标;

# -x 选项是指显示出扩展统计信息(即显示所有 I/O 指标)

$ iostat -d -x 1

3

%util :磁盘 I/O 使用率;

r/s+ w/s :是 IOPS;

rkB/s+wkB/s :是吞吐量;

r_await+w_await :是响应时间。

4.iotop ,pidstat // 按照 I/O 大小对进程排序

$ iotop

Total DISK READ : 0.00 B/s | Total DISK WRITE : 7.85 K/s

Actual DISK READ: 0.00 B/s | Actual DISK WRITE: 0.00 B/s

    TID PRIO USER  DISK READ DISK WRITE SWAPIN IO> COMMAND

15055  be/3 root 0.00 B/s 7.85 K/s 0.00 % 0.00 % systemd-journald

# -d 可以显示进程对于磁盘io的情况

$ pidstat -d 1

15:08:35 UID PID kB_rd/s kB_wr/s kB_ccwr/s iodelay Command

15:08:36 0 18940 0.00 45816.00 0.00 96 python

15:08:36 UID PID kB_rd/s kB_wr/s kB_ccwr/s iodelay Command

15:08:37 0 354 0.00 0.00 0.00 350 jbd2/sda1-8

15:08:37 0 18940 0.00 46000.00 0.00 96 python

15:08:37 0 20065 0.00 0.00 0.00 1503 kworker/u4:2

5.strace // 观察系统调用情况

# 18940是进程号

$ strace -p 18940

strace: Process 18940 attached

...

mmap(NULL, 314576896, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0f7aee9000

mmap(NULL, 314576896, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0f682e8000

# 可以看出来这里write写了300M数据

write(3, "2018-12-05 15:23:01,709 - __main"..., 314572844 ) = 314572844

munmap(0x7f0f682e8000, 314576896) = 0

write(3, "\n", 1) = 1

munmap(0x7f0f7aee9000, 314576896) = 0

close(3) = 0

# 这里可以看出来操作的是“获取 /tmp/logtest.txt.1 的状态”

stat("/tmp/logtest.txt.1", {st_mode=S_IFREG|0644, st_size=943718535, ...}) = 0

6. lsof //查看进程打开的文件情况

# FD:表示文件描述符号,

# TYPE:表示文件类型,

# NAME:表示文件路径

$ lsof -p 18940

COMMAND    PID     USER  FD   TYPE  DEVICE SIZE/OFF NODE    NAME

python      18940     root    cwd  DIR    0,50      4096      1549389  /

python      18940     root     rtd   DIR    0,50     4096       1549389 /

python     18940     root      2u CHR    136,0      0t0        3   /dev/pts/0

python      18940    root      3w  REG   8,1       117944320 303 /tmp/logtest.txt

7. fio

# direct,表示是否跳过系统缓存。1就表示跳过系统缓存。

# iodepth,表示使用异步 I/O(asynchronous I/O,简称 AIO)时,同时发出的 I/O 请求上限。

# rw,表示 I/O 模式。我的示例中, read/write 分别表示顺序读 / 写,而 randread/randwrite 则分别表示随机读 / 写。

# ioengine,表示 I/O 引擎,它支持同步(sync)、异步(libaio)、内存映射(mmap)、网络(net)等各种 I/O 引擎。libaio 表示使用异步 I/O。

# bs,表示 I/O 的大小, 4K(这也是默认值)。

# filename,表示文件路径,当然,它可以是磁盘路径(测试磁盘性能),也可以是文件路径(测试文件系统性能)。不过注意,用磁盘路径测试写,会破坏这个磁盘中的文件系统,所以在使用前,你一定要事先做好数据备份。

# 随机读

fio -name=randread -direct=1 -iodepth=64 -rw=randread -ioengine=libaio -bs=4k -size=1G -numjobs=1 -runtime=1000 -group_reporting -filename=/dev/sdb

# 随机写

fio -name=randwrite -direct=1 -iodepth=64 -rw=randwrite -ioengine=libaio -bs=4k -size=1G -numjobs=1 -runtime=1000 -group_reporting -filename=/dev/sdb

# 顺序读

fio -name=read -direct=1 -iodepth=64 -rw=read -ioengine=libaio -bs=4k -size=1G -numjobs=1 -runtime=1000 -group_reporting -filename=/dev/sdb

# 顺序写

fio -name=write -direct=1 -iodepth=64 -rw=write -ioengine=libaio -bs=4k -size=1G -numjobs=1 -runtime=1000 -group_reporting -filename=/dev/sdb

展示报告内容:

read: (g=0): rw=read, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=libaio, iodepth=64fio-3.1

Starting 1 process

Jobs: 1 (f=1): [R(1)][100.0%][r=16.7MiB/s,w=0KiB/s][r=4280,w=0 IOPS][eta 00m:00s]

read: (groupid=0, jobs=1): err= 0: pid=17966: Sun Dec 30 08:31:48 2018

   read: IOPS=4257, BW=16.6MiB/s (17.4MB/s)(1024MiB/61568msec)

# slat ,是指从 I/O 提交到实际执行 I/O 的时长(Submission latency);

# clat ,是指从 I/O 提交到 I/O 完成的时长(Completion latency);

# lat ,指的是从 fio 创建 I/O 到 I/O 完成的总时长。

slat (usec): min=2, max=2566, avg= 4.29, stdev=21.76

clat (usec): min=228, max=407360, avg=15024.30, stdev=20524.39

   lat (usec): min=243, max=407363, avg=15029.12, stdev=20524.26

clat percentiles (usec):

| 1.00th=[ 498], 5.00th=[ 1020], 10.00th=[ 1319], 20.00th=[ 1713],

| 30.00th=[ 1991], 40.00th=[ 2212], 50.00th=[ 2540], 60.00th=[ 2933],

| 70.00th=[ 5407], 80.00th=[ 44303], 90.00th=[ 45351], 95.00th=[ 45876],

| 99.00th=[ 46924], 99.50th=[ 46924], 99.90th=[ 48497], 99.95th=[ 49021],        | 99.99th=[404751]

# bw ,它代表吞吐量

bw ( KiB/s): min= 8208, max=18832, per=99.85%, avg=17005.35, stdev=998.94, samples=123

# iops ,其实就是每秒 I/O 的次数

iops : min= 2052, max= 4708, avg=4251.30, stdev=249.74, samples=123

lat (usec) : 250=0.01%, 500=1.03%, 750=1.69%, 1000=2.07%

lat (msec) : 2=25.64%, 4=37.58%, 10=2.08%, 20=0.02%, 50=29.86%

lat (msec) : 100=0.01%, 500=0.02%

cpu : usr=1.02%, sys=2.97%, ctx=33312, majf=0, minf=75

IO depths : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=0.1%, 32=0.1%, >=64=100.0%

    submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%

complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.1%, >=64=0.0%

issued rwt: total=262144,0,0, short=0,0,0, dropped=0,0,0

latency : target=0, window=0, percentile=100.00%, depth=64

Run status group 0 (all jobs):

     READ: bw=16.6MiB/s (17.4MB/s), 16.6MiB/s-16.6MiB/s (17.4MB/s-17.4MB/s), io=1024MiB (1074MB), run=61568-61568msec

Disk stats (read/write):

sdb: ios=261897/0, merge=0/0, ticks=3912108/0, in_queue=3474336, util=90.09%

备注:fio(Flexible I/O Tester)最常用的文件系统和磁盘 I/O 性能基准测试工具:https://github.com/axboe/fio

三、I/O性能的排查思路

可以按照下面的思路进行排查和定位,如下所示:

1. 用 iostat 发现磁盘 I/O 性能瓶颈;

2. 借助 pidstat ,定位出导致瓶颈的进程;

3. 分析进程的 I/O 行为;

4. 结合应用程序的原理,分析这些 I/O 的来源。

31f6aefb2a49bae374c90412a62ee981

参看资料:

https://github.com/axboe/fio

https://www.thomas-krenn.com/en/wiki/Linux_Storage_Stack_Diagram

Linux 性能优化实战

(原标题:性能之文件系统篇)

返回首页
返回顶部