磁盘 I/O
作者:赵坤
虚拟文件系统
I/O 调度
为了减小不同块设备的差异带来的影响,Linux 通过一个统一的通用块层,来管理各种不同的块设备。通用块层,其实是处在文件系统和磁盘驱动中间的一个块设备抽象层。它会给文件系统和应用程序发来的 I/O 请求排队,并通过重新排序、请求合并等方式,提高磁盘读写的效率。
Linux 内核支持四种 I/O 调度算法,分别是 NONE
、NOOP
、CFQ
以及 DeadLine
。
NONE
,不使用 I/O 调度算法NOOP
,先入先出CFQ(Completely Fair Scheduler)
,为每个进程维护了一个 I/O 调度队列,并按照时间片来均匀分布每个进程的 I/O 请求DeadLine
,分别为读、写请求创建了不同的 I/O 队列,可以提高机械磁盘的吞吐量,并确保达到最终期限(deadline)的请求被优先处理
每块磁盘 I/O 性能
$ iostat -d -x 1
Linux 5.4.0-42-generic (zk) 2020年09月02日 _x86_64_ (4 CPU)
Device r/s rkB/s rrqm/s %rrqm r_await rareq-sz w/s wkB/s wrqm/s %wrqm w_await wareq-sz d/s dkB/s drqm/s %drqm d_await dareq-sz aqu-sz %util
loop0 0.67 0.73 0.00 0.00 0.59 1.08 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.01
loop1 0.01 0.06 0.00 0.00 0.87 7.43 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
loop2 0.23 0.28 0.00 0.00 0.40 1.24 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.01
loop3 1.49 1.55 0.00 0.00 0.40 1.04 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.02
loop4 0.87 1.05 0.00 0.00 0.46 1.21 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.01
loop5 0.01 0.06 0.00 0.00 0.64 8.05 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
loop6 2.20 2.25 0.00 0.00 0.47 1.02 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.03
loop7 0.00 0.00 0.00 0.00 0.00 1.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
sda 0.06 1.92 0.00 0.00 30.65 31.56 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.01
sdb 6.13 277.71 1.45 19.16 1.17 45.31 8.24 166.67 6.65 44.65 0.88 20.23 0.00 0.00 0.00 0.00 0.00 0.00 0.00 1.03
其中:
- %util,就是磁盘 I/O 使用率;
- r/s + w/s ,就是 IOPS;
- rkB/s+wkB/s ,就是吞吐量;
- r_await+w_await ,就是响应时间。
进程 I/O 性能
$ pidstat -d 1
Average: UID PID kB_rd/s kB_wr/s kB_ccwr/s iodelay Command
Average: 0 282 -1.00 -1.00 -1.00 0 jbd2/sdb5-8
Average: 1000 2524 0.00 11.96 0.00 0 chrome
追踪系统调用
如何知道某个进程当前正在读写哪一个文件?
$ 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(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
stat("/tmp/logtest.txt.1", {st_mode=S_IFREG|0644, st_size=943718535, ...}) = 0
查看进程打开的文件列表
$ 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