性能分析之IO分析-从IO高到具体文件

IO的性能分析一直是性能分析的重点之一,分析的思路是:

在代码的逻辑清晰的状况下,是彻底能够知道哪些文件是频繁读写的。可是对性能分析人员来讲,一般是面对一个不是本身编写的系统,有时仍是多个团队合做产生的系统。这时就会出现不少的推诿和争执。若是能够迅速地把问题到一个段具体的代码,到一个具体的文件,那就能够提升沟通的效率。node

一般状况在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 为例,源码以下:linux

#!/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
扩展过的脚本以下:ios

#!/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
建立时间:-shell

这个分析思路在任何一个系统中均可以说是能用的,只是不一样的系统用的工具不一样。此次用的环境是CentOS,那在其余的系统中,只能找到相对应的其余工具了。工具

再次强调,了解原理、理清思路是性能分析的重点。工具的使用是为了验证思路的正确性。千万不要舍本逐末。性能