共计 3765 个字符,预计需要花费 10 分钟才能阅读完成。
IO 的性能剖析始终是性能剖析的重点之一,剖析的思路是:
在代码的逻辑清晰的状况下,是齐全能够晓得哪些文件是频繁读写的。然而对性能剖析人员来说,通常是面对一个不是本人编写的零碎,有时还是多个团队单干产生的零碎。这时就会呈现很多的推诿和争执。如果能够迅速地把问题到一个段具体的代码,到一个具体的文件,那就能够进步沟通的效率。
通常状况在 linux 环境下,通过 vmstat 或者 iostat 命令能够发现磁盘 IO 的异样,能够看到零碎级的磁盘读写量及 CPU 占用率,但无奈明确定位到是什么过程在作怪,装置 iotop 后,能够定位到过程,但并不知道改过程在操作什么文件。
本文是思考从零碎级的工具来实现这个操作,比拟具备通用性。在这之前须要先了解一下文件的一个重要的属性:inode。什么是 inode 呢?先来看一个示意图:
磁盘上最小的存储单元是扇区 sector,每 8 个扇区组成一个块 block(4096 字节)。如下所示:
[root@7DGroup2 ~]# tune2fs -l /dev/vda1|grep Block
Block count: 10485504
Block size: 4096
Blocks per group: 32768
[root@7DGroup2 ~]#
文件的存储就是由这些 块组成的,当块多了之后就成了如下这样(其实磁盘上的块比这个图中多得多,这里只是示意图):
其中红色的这部分是存储的文件,咱们通常在文件系统中间接 ls 或者用其余命令操作文件的时候是依据门路来操作的,那些是下层的命令。当咱们执行了一个命令之后,操作系统会来找到这些文件做相应的操作,怎么找到这些文件呢,那就须要 inode 了。Inode 用来存储这些文件的元信息,也就是索引节点,它包含的信息有:
· 字节数
· User ID
· Group ID
· 读、写、执行权限
· 工夫戳,共有三个:ctime 指 inode 上一次变动的工夫,mtime 指文件内容上一次变动的工夫,atime 指文件上一次关上的工夫
· 链接数,有多少文件名指向这个 inode
· 文件数据 block 的地位
通过这些信息,咱们能力实现对文件的操作。这个 inode 其实也是存储在磁盘上的,也须要占用一些空间,如上图中的绿色局部所示。
当咱们在零碎级看到 IO 过高的时候,比方下图所示:
从上图能够看到,这零碎简直所有的 CPU 都在等 IO。这时怎么办?就用咱们后面提到的剖析的思路,查看过程级和线程级的 IO,进而找到具体的文件。上面咱们来具体实现。
这里咱们用的是 systemtap,这个工具 7Dgroup 之前的文章中提到的,但没有开展说。前面如果有可能咱们再多写些相似的工具原理和应用办法。
Systemtap 的逻辑图如下:
从逻辑图上看,它工作在内核层面,不是 shell 的层面。
SystemTap 为咱们开启了一扇通往零碎内核的大门,SystemTap 自带的 examples 中提供一些磁盘 IO 相干的监控例子。
以 iotop.stp 为例,源码如下:
#!/usr/bin/stap
global reads, writes, total_io
probe vfs.read.return {reads[execname()] += bytes_read
}
probe vfs.write.return {writes[execname()] += bytes_written
}
# print top 10 IO processes every 5 seconds
probe timer.s(5) {foreach (name in writes)
total_io[name] += writes[name]
foreach (name in reads)
total_io[name] += reads[name]
printf ("%16s\t%10s\t%10s\n", "Process", "KB Read", "KB Written")
foreach (name in total_io- limit 10)
printf("%16s\t%10d\t%10d\n", name,
reads[name]/1024, writes[name]/1024)
delete reads
delete writes
delete total_io
print("\n")
}
执行的后果是:每隔 5 秒打印读写总量排前 10 位的过程。
该脚本有两个问题:
依照过程名字统计,存在统计误差,过程名统一,但 PID 不一样的过程,都统计到一起;
咱们仍然不能晓得过程操作了什么文件。
通过对 probe 点的剖析(sudo stap -L’vfs.{write,read}’),咱们能够晓得,vfs.read,vfs.write 有局部变量 ino 能够利用,ino 是文件的 inode,这样咱们就能够明确的探测到读写量最多的过程及文件。
$ sudo stap -L ‘vfs.{write,read}’
vfs.read file:long pos:long buf:long bytes_to_read:long dev:long devname:string ino:long name:string argstr:string $file:struct file* $buf:char $count:size_t $pos:loff_t
vfs.write file:long pos:long buf:long bytes_to_write:long dev:long devname:string ino:long name:string argstr:string $file:struct file* $buf:char const $count:size_t $pos:loff_t
扩大过的脚本如下:
#!/usr/bin/stap
global reads, writes, total_io
probe vfs.read.return {reads[execname(),pid(),ino] += bytes_read
}
probe vfs.write.return {writes[execname(),pid(),ino] += bytes_written
}
# print top 10 IO processes every 5 seconds
probe timer.s(5) {foreach ([name,process,inode] in writes)
total_io[name,process,inode] += writes[name,process,inode]
foreach ([name,process,inode] in reads)
total_io[name,process,inode] += reads[name,process,inode]
printf ("%16s\t%8s\t%8s\t%10s\t%10s\n", "Process", "PID", "inode", "KB Read", "KB Written")
foreach ([name,process,inode] in total_io- limit 10)
printf("%16s\t%8d\t%8d\t%10d\t%10d\n", name,process,inode,
reads[name,process,inode]/1024, writes[name,process,inode]/1024)
delete reads
delete writes
delete total_io
print("\n")
}
咱们来做个试验,执行 dd 命令来做一个高磁盘读写操作。
执行命令如下:
dd bs=64k count=4k if=/dev/zero of=test oflag=dsync
这条命令执行的成果是:dd 在执行时每次都会进行同步写入操作,每次从 /dev/zero 读取 64k 数据,而后写入当前目录下的 test 文件,一共反复 4K 次。在 linux 零碎中, /dev/zero 是一个非凡的文件,当你读它的时候,它会提供有限的空字符 (NULL, ASCII NUL, 0x00)。
iotop.stp 监控后果如下:
通过监控,咱们晓得了,PID 为 2978 的 dd 过程 读取 inode 为 1047 的文件,写入 inode 为 663624 的文件,这两个是读写最多的操作。
通常状况下,咱们并不知道 inode 对应文件的地位,能够通过 find / -inum 1047 找到对应的文件。
通过 stat 命令,咱们能够看到文件 inode 具体的形容。
$ stat /dev/zero
文件:”/dev/zero”
大小:0 块:0 IO 块:4096 字符非凡文件
设施:5h/5d Inode:1047 硬链接:1 设施类型:1,5
权限:(0666/crw-rw-rw-) Uid:(0/ root) Gid:(0/ root)
环境:system_u:object_r:zero_device_t:s0
最近拜访:2017-05-02 10:50:03.242425632 +0800
最近更改:2017-05-02 10:50:03.242425632 +0800
最近改变:2017-05-02 10:50:03.242425632 +0800
创立工夫:-
这个剖析思路在任何一个零碎中都能够说是能用的,只是不同的零碎用的工具不同。这次用的环境是 CentOS,那在其余的零碎中,只能找到绝对应的其余工具了。
再次强调,理解原理、理清思路是性能剖析的重点。工具的应用是为了验证思路的正确性。千万不要本末倒置。