Linux 监控之 IO

2014-05-03 linux monitor

简单介绍下 Linux 中与 IO 相关的内容。

简介

可以通过如下命令查看与 IO 相关的系统信息。

# tune2fs -l /dev/sda7                       ← 读取superblock信息
# blockdev --getbsz /dev/sda7                ← 获取block大小
# tune2fs -l /dev/sda7 | grep "Block size"   ← 同上
# dumpe2fs /dev/sda7 | grep "Block size"     ← 同上
# stat /boot/ | grep "IO Block"              ← 同上
# fdisk -l                                   ← 硬盘的扇区大小(Sector Size)

WiKi 中的定义:A “block”, a contiguous number of bytes, is the minimum unit of memory that is read from and written to a disk by a disk driver。

块是文件系统的抽象,而非磁盘的属性,一般是 Sector Size 的倍数;扇区大小则是磁盘的物理属性,它是磁盘设备寻址的最小单元。另外,内核中要求 Block_Size = Sector_Size * (2的n次方),且 Block_Size <= 内存的 Page_Size (页大小)。

磁盘类型

主要是要获取当前系统使用的什么类型的磁盘 (SCSI、IDE、SSD等),甚至是制造商、机器型号、序列号等信息。

$ dmesg | grep scsi

ioprofile 业务级

ioprofile 命令本质上等价于 lsof + strace,可以查看当前进程。

blktrace

blktrace 是块层 IO 路径监控和分析工具,作者 Jens Axboe 是内核 IO 模块的维护者,目前就职于 FusionIO,同时他还是著名 IO 评测工具 fio 的作者,使用它可以深入了解 IO 通路。

# yum install blktrace                    # 在CentOS中安装
$ make                                    # 解压源码后直接安装
$ man -l doc/blktrace.8                   # 查看帮助

其源码可以从 brick.kernel.dk 下载,详细使用参考 blktrace User Guide

原理

该工具包括了内核空间和用户空间两部分实现,内核空间里主要是给块层 IO 路径上的关键点添加 tracepoint,然后借助于 relayfs 系统特性将收集到的数据写到 buffer 去,再从用户空间去收集。

目前,内核空间部分的代码已经集成到主线代码里面去了,可以看看内核代码 block/blktrace.c 文件是不是存在,编译的时候把对应的这个 trace 选项选择上就可以了。

$ grep 'CONFIG_BLK_DEV_IO_TRACE' /boot/config-`uname -r`

大部分实现代码在 blktrace.c,利用 tracepoint 特性,注册了一些 trace 关键点,可以查看 Documentation/tracepoint.txt 文件;交互机制利用了 relayfs 特性,看看 Documentation/filesystems/relay.txt

此时捞取的信息还比较原始,可以通过用户空间的 blkparse、btt、seekwatcher 这样的工具来分析收集到的数据。

注意,使用之前要确保 debugfs 已经挂载,默认会挂载在 /sys/kernel/debug

使用

典型的使用如下,其中 /dev/sdaa、/dev/sdc 作为 LVM volume adb3/vol。

# blktrace -d /dev/sda -o - | blkparse -i - -o blkparse.out       # 简单用法,Ctrl-C退出
# btrace /dev/sda                                                 # 同上

# blktrace /dev/sdaa /dev/sdc &                                   # 离线处理。1. 后台运行采集
% mkfs -t ext3 /dev/adb3/vol                                      # 2. 做些IO操作
% kill -15 9713                                                   # 3. 停止采集
% blkparse sdaa sdc sdo > events                                  # 4. 解析后查看

在 blktrace 中,-d 表示监控哪个设备,-o 表示将监控输出到标准输出;在 blkparse 中,-i 表示从标准输入获取信息,-o 表示将解析的内容记录在 blkparse.out 。

如下是输出的详细信息。

monitor io blktrace

其中 event 对应了事件表;后面一列代表了操作类型,包括了 R(read)、W(write)、B(barrier operation)、S(synchronous operation),其中 event 有如下类型:

事件说明源码(block目录下) SetPosition
AIO was remapped to a different deviceblk-core.c/trace_block_remap
BIO bouncedbounce.c/trace_block_bio_bounce
CIO completionblk-core.c/trace_block_rq_complete
DIO issued to driverelevator.c/trace_block_rq_issue
FIO front merged with request on queueblk-core.c/trace_block_bio_frontmerge
GGet requestblk-core.c/trace_block_getrq
IIO inserted onto request queueelevator.c/trace_block_rq_insert
MIO back merged with request on queueblk-core.c/trace_block_bio_backmerge
PPlug requestblk-core.c/trace_block_plug
QIO handled by request queue codeblk-core.c/trace_block_bio_queue
SSleep requestblk-core.c/trace_block_sleeprq
TUnplug due to timeoutblk-core.c/trace_block_unplug_timer
UUnplug requestblk-core.c/trace_block_unplug_io
XSplitbio.c/trace_block_split

详解

仍以如下简单命令为例。

$ blktrace -d /dev/sda -o sda                 # 输出 sda.blktrace.N 文件,N 为物理 CPU 个数。
$ ls /sys/kernel/debug/block/sda              # 查看debugfs中的文件
dropped  msg  trace0  trace1  trace2  trace3
$ blkparse -i sda.blktrace.0                  # 解析成可读内容
$ blkrawverify sda                            # 校验,其中sda为blktrace的-o选项

其中 blktrace 通过 ioctl() 执行 BLKTRACESETUP、BLKTRACESTART、BLKTRACESTOP、BLKTRACETEARDOWN 操作,此时会在 debugfs 目录的 block/DEV 目录下写入数据。

FIO

FIO 是个非常强大的 IO 性能测试工具,其作者 Jens Axboe 是 Linux 内核 IO 部分的 maintainer,可以毫不夸张的说,如果你把所有的 FIO 参数都搞明白了,基本上就把 Linux IO 协议栈的问题搞的差不多明白了。

一个 IO 压测工具,源码以及二进制文件可以参考 github-axboe,或者直接从 freecode.com 上下载。另外,该工具同时提供了一个图形界面 gfio 。

在 CentOS 中可以通过如下方式安装。

# yum --enablerepo=epel install fio

源码编译

可以直接从 github 上下载源码,然后通过如下方式进行编译。

----- 编译,注意依赖libaio
$ make

----- 查看帮助
$ man -l fio.1

----- 通过命令行指定参数,进行简单测试
$ fio --name=global --rw=randread --size=128m --name=job1 --name=job2

----- 也可以通过配置文件进行测试
$ cat foobar.fio
[global]
rw=randread
size=128m
[job1]
[job2]
$ fio foobar.fio

可以通过命令行启动,不过此时参数较多,可以使用配置文件。

源码解析

其版本通过 FIO_VERSION 宏定义,并通过 fio_version_string 变量定义。

main()
  |-parse_options()
  |  |-parse_cmd_line()                    解析命令行,如-i显示所有的ioengines
  |  |  `-add_job()                        file1: xxxxxx 打印job信息
  |  `-log_info()                          fio-2.10.0
  `-fio_backend()
     |-create_disk_util_thread()           用于实时显示状态
     |  |-setup_disk_util()
     |  `-disk_thread_main()               通过pthread创建线程
     |     `-print_thread_status()
     |
     |-run_threads()                       Starting N processes
     |  |-setup_files()                    Laying out IO file(s)
     |  |-pthread_create()                 如果配置使用线程,调用thread_main
     |  `-fork()                           或者调用创建进程,同样为thread_main
     |
     |-show_run_stats()
        `-show_thread_status_normal()      用于显示最终的状态
           |-show_latencies()              显示lat信息
           `-... ...                       CPU、IO depth

ioengines 通过 fio_libaio_register() 类似的函数初始化。

其它

ionice

获取或设置程序的 IO 调度与优先级。

ionice [-c class] [-n level] [-t] -p PID...
ionice [-c class] [-n level] [-t] COMMAND [ARG]

----- 获取进程ID为89、91的IO优先级
$ ionice -p 89 91

参考

Block IO Layer Tracing: blktrace 介绍 blktrace 命令的使用;关于内核的 trace 功能参考 Kernel Trace Systems