Linux下的IO监控与分析
Linux下的IO监控与分析
近期要在公司内部做个Linux IO方面的培训, 整理下手头的资料给大家分享下
各种IO监视工具在Linux IO 体系结构中的位置
源自 Linux Performance and Tuning Guidelines.pdf
1 系统级IO监控
iostat
iostat -xdm 1 # 个人习惯
avgrq-sz = ( rMB/s + wMB/s) * 2048 / (r/s + w/s) # 2048 为 1M / 512
2 进程级IO监控
iotop 和 pidstat (仅rhel6u系列)
# -u CPU使用率
# -t 以线程为统计单位
# 1 1秒统计一次
block_dump, iodump
iotop.stp
但是也没有办法跟业务层的read,write联系在一起,同时颗粒度较粗,没有办法告诉你,当前进程读写了哪些文件? 耗时? 大小 ?
3 业务级IO监控
ioprofile
ioprofile 命令本质上是 lsof + strace, 具体下载可见 http://code.google.com/p/maatkit/
ioprofile 可以回答你以下三个问题:
1 当前进程某时间内,在业务层面读写了哪些文件(read, write)?
2 读写次数是多少?(read, write的调用次数)
3 读写数据量多少?(read, write的byte数)
假设某个行为会触发程序一次IO动作,例如: "一个页面点击,导致后台读取A,B,C文件"
============================================
./io_event # 假设模拟一次IO行为,读取A文件一次, B文件500次, C文件500次
ioprofile -p `pidof io_event` -c count # 读写次数
ioprofile -p `pidof io_event` -c times # 读写耗时
ioprofile -p `pidof io_event` -c sizes # 读写大小
注: ioprofile 仅支持多线程程序,对单线程程序不支持. 对于单线程程序的IO业务级分析,strace足以。
总结:
ioprofile本质上是strace,因此可以看到read,write的调用轨迹,可以做业务层的io分析(mmap方式无能为力)
4 文件级IO监控
文件级IO监控可以配合/补充"业务级和进程级"IO分析
文件级IO分析,主要针对单个文件, 回答当前哪些进程正在对某个文件进行读写操作.
1 lsof 或者 ls /proc/pid/fd
2 inodewatch.stp
lsof 告诉你 当前文件由哪些进程打开
lsof ../io # io目录 当前由 bash 和 lsof 两个进程打开
lsof 命令 只能回答静态的信息, 并且"打开" 并不一定"读取", 对于 cat ,echo这样的命令, 打开和读取都是瞬间的,lsof很难捕捉
可以用 inodewatch.stp 来弥补
stap inodewatch.stp major minor inode # 主设备号, 辅设备号, 文件inode节点号
stap inodewatch.stp 0xfd 0x00 523170 # 主设备号, 辅设备号, inode号,可以通过 stat 命令获得
5 IO模拟器
iotest.py # 见附录
开发人员可以 利用 ioprofile (或者 strace) 做详细分析系统的IO路径,然后在程序层面做相应的优化。
但是一般情况下调整程序,代价比较大,尤其是当不确定修改方案到底能不能有效时,最好有某种模拟途径以快速验证。
以为我们的业务为例,发现某次查询时,系统的IO访问模式如下:
访问了A文件一次
访问了B文件500次, 每次16字节, 平均间隔 502K
访问了C文件500次, 每次200字节, 平均间隔 4M
这里 B,C文件是交错访问的, 既
1 先访问B,读16字节,
2 再访问C,读200字节,
3 回到B,跳502K后再读16字节,
4 回到C,跳4M后,再读200字节
5 重复500次
strace 文件如下:
一个简单朴素的想法, 将B,C交错读,改成先批量读B , 再批量读C,因此调整strace 文件如下:
将调整后的strace文件, 作为输入交给 iotest.py, iotest.py 按照 strace 文件中的访问模式, 模拟相应的IO
iotest.py -s io.strace -f fmap
fmap 为映射文件,将strace中的222,333等fd,映射到实际的文件中
===========================
111 = /opt/work/io/A.data
222 = /opt/work/io/B.data
333 = /opt/work/io/C.data
===========================
6 磁盘碎片整理
一句话: 只要磁盘容量不常年保持80%以上,基本上不用担心碎片问题。
如果实在担心,可以用 defrag 脚本
7 其他IO相关命令
blockdev 系列
=======================================
blockdev --getbsz /dev/sdc1 # 查看sdc1盘的块大小
block blockdev --getra /dev/sdc1 # 查看sdc1盘的预读(readahead_kb)大小
blockdev --setra 256 /dev/sdc1 # 设置sdc1盘的预读(readahead_kb)大小,低版的内核通过/sys设置,有时会失败,不如blockdev靠谱
=======================================
附录 iotest.py
ctypes optparse = ===== line line.strip() != =, , dest==, metavar=, , dest==, metavar== options.strace_filename None: parser.error( os.path.exists(options.strace_filename): parser.error( options.fileno_filename None: parser.error( os.path.exists(options.strace_filename): parser.error(
=== r
i = _match None:
_type, _fn, _count, _off = _match.group(1), _match.group(2), _match.group(3), _match.group(4= _off.replace(, ).replace(, ).replace(, ).replace(, = _count.replace(, ).replace(, ).replace(, ).replace(,
== i i.strip().startswith():
_split = [j.strip() j i.split( len(_split) != 2:
fno, fname = _split[0], _split[1== i = open(i,
= str(_f.fileno())
= 4 * 1024
i 1] = rfmap[fmap[i[1]]]
to_read = max(to_read, int(i[2
_c_char_buf = _f