I/O 栈的全景图:
把 Linux 存储系统的 I/O 栈,由上到下分为三个层次,分别是文件系统层、通用块层和设备层。
文件系统层,包括虚拟文件系统和其他各种文件系统的具体实现。它为上层的应用程序,提供标准的文件访问接口;对下会通过通用块层,来存储和管理磁盘数据。
通用块层,包括块设备 I/O 队列和 I/O 调度器。它会对文件系统的 I/O 请求进行排队,再通过重新排序和请求合并,然后才要发送给下一级的设备层。
设备层,包括存储设备和相应的驱动程序,负责最终物理设备的 I/O 操作。
磁盘I/O性能指标:
使用率,是指磁盘处理 I/O 的时间百分比。过高的使用率(比如超过 80%),通常意味着磁盘 I/O 存在性能瓶颈。
饱和度,是指磁盘处理 I/O 的繁忙程度。过高的饱和度,意味着磁盘存在严重的性能瓶颈。当饱和度为 100% 时,磁盘无法接受新的 I/O 请求。
IOPS(Input/Output Per Second),是指每秒的 I/O 请求数。
吞吐量,是指每秒的 I/O 请求大小。
响应时间,是指 I/O 请求从发出到收到响应的间隔时间。
注意:使用率只考虑有没有 I/O,而不考虑 I/O 的大小。换句话说,当使用率是 100% 的时候,磁盘依然有可能接受新的 I/O 请求。
I/O 性能分析的“指标筛选”清单
常用命令及指标参数:
1.df
root@node02:~# df -ihT
Filesystem Type Inodes IUsed IFree IUse% Mounted on
udev devtmpfs 482K 466 482K 1% /dev
tmpfs tmpfs 490K 929 489K 1% /run
/dev/mapper/ubuntu--vg-ubuntu--lv ext4 1.6M 148K 1.4M 10% /
tmpfs tmpfs 490K 1 490K 1% /dev/shm
tmpfs tmpfs 490K 3 490K 1% /run/lock
tmpfs tmpfs 490K 18 490K 1% /sys/fs/cgroup
/dev/sda2 ext4 64K 305 64K 1% /boot
tmpfs tmpfs 490K 13 490K 1% /run/user/0
常用参数:
-h 或 --human-readable:
将文件系统的大小以人类可读的方式显示,以便更容易理解,例如使用 KB、MB、GB 等单位。
-a 或 --all:显示所有文件系统,包括系统中特殊文件系统(如 proc)。
-T 或 --print-type:显示文件系统类型。
-i 或 --inodes:显示 inode 使用情况。
–total:显示所有列的总计。
-x 或 --exclude:排除特定的文件系统。
–sync:在显示文件系统使用情况之前,同步磁盘。
2.fio
性能测试工具,主要来测试磁盘的 IOPS、吞吐量以及响应时间等核心指标。
# 格式
fio [options] [jobfile | options]
# 简单的随机读写测试:
fio --name=mytest --ioengine=rados-cls --rw=randwrite --bs=4k --numjobs=16 --size=10G --runtime=300
# 从作业文件运行测试:
fio mytestjobfile
常用选项:
–name: 为作业指定一个名称。
–ioengine: 指定 I/O 引擎,如 sync、mmap、rados-cls 等。
–rw: 指定读写模式,如 randwrite、randread、write、randrw 等。
–bs: 指定块大小,如 4k、8k、16k 等。
–numjobs: 指定并发作业数。
–size: 指定测试文件或块设备的大小。
–runtime: 指定测试运行时间。
–time_based: 使用时间为基准而不是大小。
3.iostat
iostat 只提供磁盘整体的 I/O 性能数据,缺点在于,并不能知道具体是哪些进程在进行磁盘读写。
root@node02:~# iostat -d -x 1
Linux 4.15.0-213-generic (node02) 02/01/2024 _x86_64_ (2 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.00 0.00 0.00 2.50 0.00 0.00 0.00
fd0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 54.00 0.00 0.00 4.00 0.00 54.00 0.00
scd1 0.00 0.00 0.05 0.00 0.00 0.00 0.00 0.00 0.35 0.00 0.00 22.35 0.00 0.35 0.00
sda 0.31 5.84 18.44 38.43 0.02 1.65 4.91 22.07 2.15 2.95 0.02 58.71 6.58 0.23 0.14
dm-0 0.32 7.50 18.32 39.88 0.00 0.00 0.00 0.00 2.86 2.53 0.02 56.40 5.32 0.18 0.14
指标解释如下:
添加参数"-k"后指标解释如下:
tps: 每秒传输的 I/O 请求次数。
kB_read/s 和 kB_wrtn/s: 每秒读取和写入的数据量。
kB_read 和 kB_wrtn: 读取和写入的总数据量。
这些指标中,你要注意:
%util ,就是我们前面提到的磁盘 I/O 使用率;
r/s+ w/s ,就是 IOPS;
rkB/s+wkB/s ,就是吞吐量;
r_await+w_await ,就是响应时间。
常用选项:
-c: 显示 CPU 使用情况。
-d: 显示磁盘统计信息。
-k: 以千字节为单位显示数据传输速率。
-t: 在输出中包含时间戳。
-x: 显示详细磁盘 I/O 统计信息。
4.pidstat
可以观察进程的 I/O 情况。
root@node02:~# pidstat -d
Linux 4.15.0-213-generic (node02) 02/01/2024 _x86_64_ (2 CPU)
11:16:51 AM UID PID kB_rd/s kB_wr/s kB_ccwr/s iodelay Command
11:16:51 AM 0 1 9.21 3.72 0.51 69 systemd
指标解释如下:
用户 ID(UID)和进程 ID(PID) 。
每秒读取的数据大小(kB_rd/s) ,单位是 KB。
每秒发出的写请求数据大小(kB_wr/s) ,单位是 KB。
每秒取消的写请求数据大小(kB_ccwr/s) ,单位是 KB。
块 I/O 延迟(iodelay),包括等待同步块 I/O 和换入块 I/O 结束的时间,单位是时钟周期。
基本命令格式:
pidstat [options] [interval [count]] -p <pid>
interval: 指定显示统计信息的时间间隔(秒)。
count: 指定显示统计信息的次数。
-p : 指定要监视的进程的进程ID。
常用参数:
-u 或 --cpu: 显示 CPU 使用情况。
%usr: 用户空间占用 CPU 的百分比。
%system: 内核空间占用 CPU 的百分比。
%guest: 用作虚拟机的百分比。
%CPU: 用户和系统空间的总百分比。
-r 或 --memory: 显示内存使用情况。
KB_rd/s 和 KB_wr/s: 每秒读取和写入的内存数据量。
KB_ccwr/s: 每秒清理缓存的数据量。
-d 或 --disk: 显示磁盘 I/O 统计信息。
rd_sec/s 和 wr_sec/s: 每秒读取和写入的扇区数。
rd_ticks/s 和 wr_ticks/s: 每秒读取和写入的毫秒数。
-t 或 --socket: 显示套接字统计信息。
active/s 和 passive/s: 每秒活跃和被动套接字的数量。
-w 或 --task: 显示任务切换统计信息。
cswch/s: 每秒上下文切换的数量。
5.iotop
可以观察进程的 I/O 情况。
root@node02:~# iotop
Total DISK READ : 0.00 B/s | Total DISK WRITE : 0.00 B/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
112491 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.04 % [kworker/u256:3]
指标参数如下:
前两行分别表示,进程的磁盘读写大小总数和磁盘真实的读写大小总数。因为缓存、缓冲区、I/O 合并等因素的影响,它们可能并不相等。
TID (Thread ID):表示线程的唯一标识符。每个线程都有一个唯一的 TID。
PRIO (Priority):表示进程的优先级。较低的数字表示较高的优先级。
USER:表示进程所属的用户。
DISK READ:表示进程从磁盘读取的数据量。在你提供的输出中,显示为每秒读取的字节数(B/s)。
DISK WRITE:表示进程向磁盘写入的数据量。在你提供的输出中,显示为每秒写入的字节数(B/s)。
SWAPIN:表示进程从交换空间中交换进主内存的数据量。
IO>:表示进程的总体 I/O 活动。在你提供的输出中,显示为每秒的 I/O 活动百分比。
COMMAND:表示正在执行的命令或进程的名称。
常用选项:
-o 或 --only: 只显示有磁盘 I/O 活动的进程。
-b 或 --batch: 以批处理模式运行,不需要交互。
-n 或 --interval=: 指定更新显示的时间间隔。
-d 或 --delay=: 指定显示磁盘统计信息的延迟时间。
-p 或 --pid=: 仅显示指定进程的信息。
-u 或 --only: 显示 I/O 使用率而不是总体 I/O 操作。
-P 或 --processes: 显示每个进程的详细 I/O 统计信息。
-a 或 --accumulated: 显示积累的 I/O 统计信息。
交互模式:
在交互模式下,你可以使用键盘上的不同键来进行排序和切换显示选项。例如,按下r键可以按照读取速度进行排序,按下w键可以按照写入速度进行排序。
6.strace
strace 是一个用于跟踪系统调用和信号的命令行工具。它可以帮助你监视一个进程的系统调用,了解程序在执行时与操作系统之间的交互。
语法格式:
strace [options] command [args]
command: 要执行的命令。
args: 命令的参数。
常用选项:
-e trace=…:指定要跟踪的系统调用,如-e trace=open表示只跟踪文件打开操作。
-o file:将输出写入文件而不是标准错误。
-p pid:跟踪已经运行的进程,而不是启动新的进程。
-c:统计每个系统调用的次数、耗时等。
-t:在输出中包含时间戳。
-f:跟踪由fork产生的子进程。
-T:表示显示系统调用的时长
-tt:表示显示跟踪时间
6.filetop
基于 Linux 内核的 eBPF(extended Berkeley Packet Filters)机制,主要跟踪内核中文件的读写情况,并输出线程 ID(TID)、读写大小、读写类型以及文件名称。
root@node02:/usr/share/bcc/tools# ./filetop -C
Tracing... Output every 1 secs. Hit Ctrl-C to end
16:14:57 loadavg: 0.16 0.19 0.10 1/353 17223
TID COMM READS WRITES R_Kb W_Kb T FILE
17223 filetop 1 0 4 0 R id
filetop 输出了 8 列内容,分别是线程 ID、线程命令行、读写次数、读写的大小(单位 KB)、文件类型以及读写的文件名称。
7.opensnoop
opensnoop 是一个用于跟踪系统中文件被打开的命令行工具。它能够捕捉并显示哪些进程在打开文件,以及文件的路径等信息。通常,opensnoop 利用 Linux 内核的 ftrace 框架来实现跟踪文件打开事件。
格式:
opensnoop [options]
常用选项:
-p :指定要跟踪的进程ID。
-n :指定要跟踪的进程名称。
-t:在输出中包含时间戳。
-d :指定跟踪的持续时间。
-f :设置过滤规则,仅显示符合条件的文件打开事件。
示例:
跟踪所有文件的打开事件:
opensnoop
仅跟踪进程ID为1234的进程的文件打开事件:
opensnoop -p 1234
跟踪包含关键字 “example” 的文件打开事件:
opensnoop -f example
8.vmstat
root@node02:/usr/share/bcc/tools# vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 0 279568 118372 1699172 0 0 7 20 85 159 1 1 98 0 0
procs:
r: 运行队列的平均长度,即正在运行和等待运行的进程数量。
b: 处于非中断睡眠状态(D状态)的进程数量,表示阻塞的进程数。
memory:
swpd: 已使用的虚拟内存大小,以 KB 为单位。
free: 空闲的物理内存大小,以 KB 为单位。
buff: 用作缓冲的内存大小,以 KB 为单位。
cache: 用作缓存的内存大小,以 KB 为单位。
swap:
si: 从磁盘交换到内存的速率,以 KB/s 为单位。
so: 从内存交换到磁盘的速率,以 KB/s 为单位。
io:
bi: 块设备接收的块数量(从块设备读取的块数),每秒。
bo: 块设备发送的块数量(写入块设备的块数),每秒。
system:
in: 每秒中断的次数,包括时钟中断。
cs: 每秒上下文切换的次数。
cpu:
us: 用户空间占用 CPU 的百分比。
sy: 内核空间占用 CPU 的百分比。
id: CPU 空闲的百分比。
wa: CPU 在等待 I/O 操作完成时的百分比。
st: 虚拟机偷取时间的百分比(仅针对虚拟机环境,表示由于主机上的其他虚拟机导致的时间偷取)。
9.dstat
dstat 是一个用于实时监测系统性能的命令行工具。它能够提供关于 CPU、内存、磁盘 I/O、网络等各方面的统计信息,以帮助用户追踪系统的健康状况。
root@node02:~# dstat
You did not select any stats, using -cdngy by default.
--total-cpu-usage-- -dsk/total- -net/total- ---paging-- ---system--
usr sys idl wai stl| read writ| recv send| in out | int csw
1 1 98 0 0| 14k 40k| 0 0 | 0 0 | 168 316
1 2 97 1 0| 0 104k| 66B 892B| 0 0 | 208 358
指标解释:
–total-cpu-usage–:
usr: 用户空间占用 CPU 的百分比。
sys: 内核空间占用 CPU 的百分比。
idl: CPU 空闲的百分比。
wai: CPU 在等待 I/O 操作完成时的百分比。
stl: CPU 在被虚拟机偷取时间的百分比(仅在虚拟化环境中有意义)。
-dsk/total-:
read: 每秒从磁盘读取的数据量。
writ: 每秒写入磁盘的数据量。
-net/total-:
recv: 每秒接收的网络数据量。
send: 每秒发送的网络数据量。
—paging–:
in: 每秒从磁盘读取的页面数量(分页输入)。
out: 每秒写入磁盘的页面数量(分页输出)。
—system–:
int: 每秒中断的次数。
csw: 每秒上下文切换的次数。
基本命令格式:
dstat [options] [interval [count]]
interval: 指定显示统计信息的时间间隔(秒)。
count: 指定显示统计信息的次数。
常用选项:
-c, --cpu: 显示 CPU 使用情况。
-m, --memory: 显示内存使用情况。
-d, --disk: 显示磁盘 I/O 情况。
-n, --net: 显示网络使用情况。
-p, --proc: 显示进程相关信息。
-y, --sys: 显示系统相关信息。
-l, --load: 显示系统负载情况。
10.查看目录项、索引节点以及文件系统的缓存
/proc/meminfo
root@node02:~# cat /proc/meminfo
MemTotal: 4013248 kB
MemFree: 322036 kB
MemAvailable: 1911952 kB
Buffers: 124520 kB
Cached: 1400512 kB
SwapCached: 0 kB
Active: 929476 kB
Inactive: 806968 kB
Active(anon): 212508 kB
Inactive(anon): 400 kB
Active(file): 716968 kB
Inactive(file): 806568 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 0 kB
SwapFree: 0 kB
Dirty: 516 kB
Writeback: 0 kB
AnonPages: 211404 kB
Mapped: 378160 kB
Shmem: 1504 kB
Slab: 1011444 kB
SReclaimable: 343612 kB
SUnreclaim: 667832 kB
KernelStack: 7696 kB
PageTables: 7504 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 2006624 kB
Committed_AS: 2085904 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 0 kB
VmallocChunk: 0 kB
HardwareCorrupted: 0 kB
AnonHugePages: 0 kB
ShmemHugePages: 0 kB
ShmemPmdMapped: 0 kB
CmaTotal: 0 kB
CmaFree: 0 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
DirectMap4k: 173888 kB
DirectMap2M: 4020224 kB
DirectMap1G: 2097152 kB
总体内存信息:
MemTotal: 系统总内存。
MemFree: 未被使用的内存。
MemAvailable: 可用内存,包括用于文件缓存的内存。
Buffers: 用于存储块设备的缓冲区的内存。
Cached: 用于文件缓存的内存。
交换空间信息:
SwapTotal: 交换空间的总大小。
SwapFree: 未使用的交换空间。
活跃内存信息:
Active: 活跃的内存,正在使用或最近被使用。
Inactive: 非活跃的内存,最近没有被使用。
Active(anon): 活跃的匿名内存(进程堆栈等)。
Inactive(anon): 非活跃的匿名内存。
Active(file): 活跃的文件缓存。
Inactive(file): 非活跃的文件缓存。
内核和系统信息:
Slab: 内核 SLAB 分配器使用的内存。
SReclaimable: SLAB 中可回收的内存。
SUnreclaim: SLAB 中不可回收的内存。
KernelStack: 用于内核栈的内存。
PageTables: 页表使用的内存。
其他信息:
Dirty: 等待被写回到磁盘的脏页面的内存量。
Writeback: 正在被写回到磁盘的内存量。
CommitLimit: 内核允许系统分配的总内存大小。
Committed_AS: 系统当前已经使用的内存。
巨大页面信息:
HugePages_Total: 系统支持的大页面总数。
HugePages_Free: 空闲的大页面数量。
HugePages_Rsvd: 为了分配而保留的大页面数量。
HugePages_Surp: 超过系统限制的大页面数量。
DirectMap:DirectMap4k, DirectMap2M, DirectMap1G: 直接映射的内存。
/proc/diskstats
root@node02:~# cat /proc/diskstats
7 0 loop0 2 0 10 0 0 0 0 0 0 0 0
7 1 loop1 0 0 0 0 0 0 0 0 0 0 0
7 2 loop2 0 0 0 0 0 0 0 0 0 0 0
7 3 loop3 0 0 0 0 0 0 0 0 0 0 0
7 4 loop4 0 0 0 0 0 0 0 0 0 0 0
7 5 loop5 0 0 0 0 0 0 0 0 0 0 0
7 6 loop6 0 0 0 0 0 0 0 0 0 0 0
7 7 loop7 0 0 0 0 0 0 0 0 0 0 0
2 0 fd0 2 0 16 108 0 0 0 0 0 108 108
11 0 sr0 0 0 0 0 0 0 0 0 0 0 0
11 1 sr1 138 0 6168 48 0 0 0 0 0 48 48
8 0 sda 22809 985 2493492 41500 573819 166690 7909120 1490904 0 120244 1479080
8 1 sda1 68 0 544 24 0 0 0 0 0 24 24
8 2 sda2 125 0 8610 184 8 5 104 88 0 272 272
8 3 sda3 22531 985 2480138 41252 573811 166685 7909016 1490816 0 120204 1478748
253 0 dm-0 23474 0 2479610 56460 740496 0 8311176 1643236 0 120376 1699916
指标解释如下:
第一列(Major):
表示设备的主设备号,它用于标识设备的类型。
第二列(Minor):
表示设备的次设备号,它用于标识具体的设备。
第三列(Device):
表示设备的名称,如 sda、loop0、fd0 等。
读取/写入操作次数:
Reads: 读取操作的次数。
Read Merges: 读取操作的合并次数。
Read Sectors: 读取的扇区数。
Read Time: 读取操作的时间。
Writes: 写入操作的次数。
Write Merges: 写入操作的合并次数。
Write Sectors: 写入的扇区数。
Write Time: 写入操作的时间。
IO 等待时间:
IO in Progress: 正在进行的 I/O 操作数量。
IO Time: I/O 操作的总时间。
IO 请求队列:
IO Wait Time: I/O 请求在队列中等待的时间。
IO Wait Count: 在队列中等待的 I/O 请求的数量。
IO 操作时间统计:IO Time Weighted: 加权的 I/O 操作时间。
对于提供的示例输出:
loop0 到 loop7 表示 loopback 设备。
fd0 表示软盘设备。
sr0 和 sr1 表示光盘设备。
sda 是硬盘设备,有多个分区,分别是 sda1、sda2 和 sda3。
dm-0 是设备映射(device-mapper)的逻辑卷。
11.dmesg
dmesg 是一个用于查看和控制内核环缓冲区的 Linux 命令。它提供了有关系统启动时硬件、驱动程序和内核模块加载等方面的消息。除了启动消息外,dmesg 还可以用于查看内核运行时产生的其他消息,如硬件错误、设备连接和断开等。
格式:
dmesg [options]
常用选项:
-c, --clear: 清除内核环缓冲区。
-w, --follow: 持续监视新消息。
-n, --console-level : 设置控制台消息的记录级别。
常用的级别包括:
0 或 emerg: 紧急消息。
1 或 alert: 警报消息。
2 或 crit: 临界消息。
3 或 err: 错误消息。
4 或 warning: 警告消息。
5 或 notice: 注意消息。
6 或 info: 信息消息。
7 或 debug: 调试消息。
-r, --raw: 以原始格式显示消息。
-T, --ctime: 显示消息的时间戳。
参考文献:Linux性能优化实战