《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #20 使用fio进行I/O的基准测试

简介: 本节书摘来自华章出版社《Linux内核精髓:精通Linux内核必会的75个绝技》一书中的第3章,第3.4节,作者 竹部 晶雄、平松 雅巳,更多章节内容可以访问云栖社区“华章计算机”公众号查看

HACK #20 使用fio进行I/O的基准测试

本节介绍使用fio进行模拟各种情况的I/O基准测试的操作方法。
I/O的基准测试中有无数需要考虑的因素。是I/O依次访问还是随机访问?是通过read/write的I/O?还是通过访问mmap的空间的I/O?是单一进程发出的I/O?还是多个进程同时发出的I/O?进程是受I/O限制还是受CPU限制?等等。
如果使用fio,就不需要每次都根据不同情况来编写用于性能评估的程序,就可以模拟这些情况的I/O。
安装fio
Fedora、Ubuntu等主流发布版中都备有fio的二进制文件包。请使用yum、apt等安装fio工具包。
这里按照Fedora 13中包含的fio版本1.36来进行说明。
想要使用最新版时,请先从下列网页下载fio的源代码,再进行安装。
Git仓库
git://git.kernel.org/pub/scm/linux/kernel/git/axboe/fio.git
基本执行方法
指定记载了I/O操作模式的设置文件,然后启动fio命令,这就是fio最基本的执行方法。大多数的项目可以不使用配置文件而通过命令行选项来指定。首先举出两种分别使用命令行选项的方法和配置文件的方法的简单例子,了解基本执行方法和命令行/设置文件的对应情况。
第一个示例执行的是下列操作。
进行10MB的顺序读入。
同时,其他进程随机进行5MB的写入。
使用read(2)和write(2)进行读写。
使用Direct I/O。
在fio命令行进行这些设置时的操作如下。在当前目录下会生成读写用的文件,因此要在可以写入的目录下执行。

$ fio --name=global --direct=1 --name=read --rw=read --size=10m --name=write --rw=randwrite --size=5m

与上述命令行选项具有相同意义的配置文件如下所示。

# cat fio_exam.fio

[global]
direct=1

[readjob]
size=10m
rw=read

[writejob]
size=5m
rw=randwrite

使用这个配置文件执行fio命令如下。

$ fio simple_read.fio

命令行选项与配置文件的各项之间的关系非常明显。这里简单介绍配置文件的各项的意义。
以#开头的是注释(comment)。内容直到行尾都被忽略。
方括号表示[]作业(job)定义选项的开始。方括号内是作业的名称。作业可以任意命名。但是global这个名称是内部使用的。作业global是用来定义所有作业共同的设置项。
fio按照每个作业生成进程,生成的进程根据设置进行实际的I/O操作。因此,fio的配置文件中除了global选项以外,必须要定义多个作业。
global选项中设置了direct=1。将direct设置为1时,使用的就Direct I/O。未指定时,就等同于direct=0(经由一般页面缓存进行I/O)。
接下来定义名为readjob的作业。
readjob作业中使用size设置I/O操作的大小(字节数)。后缀m表示兆字节。后缀可以使用k、m、g、t、p。readjob作业的进程在进行了size所设置的大小的I/O后就会结束。
rw用来设置I/O模式。readjob作业中指定的是表示顺序读出的read。其他的将在下一节中介绍。
最后再定义一个名称为writejob的作业。
writejob作业将进行I/O的大小设置为5MB,I/O模式设置为随机写入(randwrite)。
按照这个设置执行fio时,首先会在当前目录下生成用于I/O的文件,进行同步处理,取消页面缓存。然后,生成与readjob作业相对应的进程和与writejob作业相对应的进程,进行各自设置的I/O操作。各作业在完成size所设置的字节数的I/O后,就会结束。所有作业结束后,结果就会显示在控制台上。
输出结果包括很多信息。这些内容将在下一节中详细介绍。
模拟实验的例子和输出的意义
现在已经掌握了基本执行方法,就可以尝试生成并执行模拟某种情况的配置文件,然后对输出进行分析。
先生成符合下列情况的配置文件。
在文件数据的基础上执行查询(query)并返回发出请求的进程有两个正在执行。每隔10毫秒接受查询的请求并执行,从接受请求到返回结果的演算过程花费5毫秒。
1个正在运行的进程,它用来将访问记录写入磁盘。记录每1秒通过direct I/O写入。通过AIO实现I/O复用(multiplexing)。
与此同时,执行文件系统备份处理。
模拟这种情况的配置文件以及其中使用的各种配置项的意义如表3-7所示。另外,模拟时间设置为执行30秒后结束。

# server_sim.fio

[global]
directory=/mnt/sdb
runtime=30
time_based

[query]
size=100m
rw=randread
ioengine=mmap
thinktime=10k
thinktime_spin=5k
filename=query.dat
numjobs=2

[log]
size=10m
rw=randrw
ioengine=libaio
iodepth=32
thinktime=1m
thinktime_blocks=2
blocksize=1k,4k
direct=1

[backup]
size=100m
rw=randrw
thinktime=1k

表3-7 fio的配置项
image
image

然后实际执行,并详细查看输出结果。

$ fio server_sim.fio

query: (g=0): rw=randread, bs=4K-4K/4K-4K, ioengine=mmap, iodepth=1
query: (g=0): rw=randread, bs=4K-4K/4K-4K, ioengine=mmap, iodepth=1
log: (g=0): rw=randrw, bs=1K-1K/4K-4K, ioengine=libaio, iodepth=32
backup: (g=0): rw=randrw, bs=4K-4K/4K-4K, ioengine=sync, iodepth=1
Starting 4 processes
query: Laying out IO file(s) (1 file(s) / 100MB)
log: Laying out IO file(s) (1 file(s) / 10MB)
backup: Laying out IO file(s) (1 file(s) / 100MB)

query: (groupid=0, jobs=1): err= 0: pid=3158
  read : io=6,740KB, bw=225KB/s, iops=56, runt= 30006msec
    clat (usec): min=6, max=124K, avg=7553.49, stdev=5995.06
    bw (KB/s) : min=  162, max=  254, per=25.31%, avg=225.24, stdev=15.52
  cpu          : usr=28.83%, sys=0.24%, ctx=3544, majf=1639, minf=75
  IO depths    : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     issued r/w: total=1685/0, short=0/0
     lat (usec): 10=2.67%, 20=0.06%, 500=0.18%, 750=0.65%, 1000=0.36%
     lat (msec): 2=1.54%, 4=15.73%, 10=58.16%, 20=17.69%, 50=2.79%
     lat (msec): 100=0.12%, 250=0.06%

query: (groupid=0, jobs=1): err= 0: pid=3159
  read : io=6,772KB, bw=226KB/s, iops=56, runt= 30008msec
    clat (usec): min=6, max=128K, avg=7470.76, stdev=6163.17
    bw (KB/s) : min=  181, max=  260, per=25.45%, avg=226.47, stdev=14.27
  cpu          : usr=28.99%, sys=0.20%, ctx=3622, majf=1630, minf=88
  IO depths    : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     issued r/w: total=1693/0, short=0/0
     lat (usec): 10=3.66%, 20=0.06%, 500=0.35%, 750=0.77%, 1000=0.06%
     lat (msec): 2=1.24%, 4=16.42%, 10=55.64%, 20=19.31%, 50=2.30%
     lat (msec): 100=0.12%, 250=0.06%

log: (groupid=0, jobs=1): err= 0: pid=3160
  read : io=39,936B, bw=1,311B/s, iops=1, runt= 30449msec
    slat (usec): min=8, max=63, avg=27.92, stdev=19.38
    clat (msec): min=36, max=16,815, avg=10042.82, stdev=5584.03
    bw (KB/s) : min=    0, max=    1, per=0.01%, avg= 0.06, stdev= 0.24
  write: io=197KB, bw=6,625B/s, iops=1, runt= 30449msec
    slat (usec): min=10, max=89, avg=33.40, stdev=22.97
    clat (msec): min=33, max=16,778, avg=11045.30, stdev=5371.05
    bw (KB/s) : min=    0, max=    7, per=0.56%, avg= 2.62, stdev= 2.59
  cpu          : usr=0.00%, sys=0.01%, ctx=31, majf=0, minf=21
  IO depths    : 1=1.1%, 2=2.2%, 4=4.5%, 8=9.0%, 16=18.0%, 32=65.2%, >=64=0.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=98.3%, 8=0.0%, 16=0.0%, 32=1.7%, 64=0.0%, >=64=0.0%
     issued r/w: total=39/50, short=0/0
     lat (msec): 50=2.25%, 2000=4.49%, >=2000=93.26%

backup: (groupid=0, jobs=1): err= 0: pid=3161
  read : io=13,556KB, bw=452KB/s, iops=112, runt= 30005msec
    clat (usec): min=419, max=104K, avg=6669.29, stdev=4584.93
    bw (KB/s) : min=  341, max=  525, per=50.82%, avg=452.29, stdev=40.41
  write: io=14,072KB, bw=469KB/s, iops=117, runt= 30005msec
    clat (usec): min=10, max=98,704, avg=79.48, stdev=2190.03
    bw (KB/s) : min=  321, max=  632, per=100.32%, avg=469.52, stdev=72.87
  cpu          : usr=0.38%, sys=0.74%, ctx=10302, majf=0, minf=28
  IO depths    : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     issued r/w: total=3389/3518, short=0/0
     lat (usec): 20=38.63%, 50=12.25%, 500=0.51%, 750=0.61%, 1000=0.04%
     lat (msec): 2=1.61%, 4=9.64%, 10=28.99%, 20=7.37%, 50=0.25%
     lat (msec): 100=0.10%, 250=0.01%

Run status group 0 (all jobs):
   READ: io=27,107KB, aggrb=890KB/s, minb=1KB/s, maxb=462KB/s, mint=30005msec, maxt=30449msec
  WRITE: io=14,269KB, aggrb=468KB/s, minb=6KB/s, maxb=480KB/s, mint=30005msec, maxt=30449msec

Disk stats (read/write):
  sdb: ios=6698/2302, merge=0/26478, ticks=48982/1143531, in_queue=1207586, util=93.27%

第一部分输出的是已执行进程的信息,分别输出了名称、I/O模式、块的大小等设置。有两个query是因为指定为numjob=2,所以要执行两个进程。
接下来第一行为query的两个段落是query作业两个进程的结果,其后显示的分别是log作业和backup作业的结果。下面对比各部分的内容,看一下各输出表示的意义。
从read:和write:开始的3行或4行表示的是关于读入和写入的数据量、平均带宽、延迟。平均带宽是将总数据量除以作业执行时间得出的值,因此在thinktime较长的作业中值较低。clat(completion latency)的行为延迟,是作业进程开始向内核发出I/O请要到完成为止的时间,即从调出read(2)等直到返回的时间。log作业由于使用的是AIO,因此多输出一个slat(submitting latency)延迟。这表示I/O发出要求滞留在作业进程内部的queue时间。
从query作业的延迟来看,平均花费7.5毫秒左右,最多花费130毫秒左右。10毫秒的查询间隔中大部分时间都耗费在等待I/O上。log作业中出现了最长16秒的延迟。这时应当重新设计系统,分散I/O负载。
小贴士:clat在read(2)或Direct I/O的write(2)中I/O实际花费的时间,而在常用的经由页面缓存的write(2)中只是将数据存放到页面缓存所需的时间。上例中backup作业的write就相当于这种情况,因此其值平均为79微秒,比其他情况短得多。
I/O depths的行表示通过AIO实现复用的I/O数与时间之间的关系。例如,log作业的IO depths中的“8=9.0%,16=18.0%”,就表示9~16个I/O同时执行的时间相当于所有执行时间的18.0%。由于I/O复用只存在于AIO的情况下,因此在log以外的作业都是“1=100%”。
从log作业的IO depths可以看出,65.2%的时间都达到复用上限值附近的19~32。这也显示I/O负载仍然过高。
最后两个段落是关于所有进程总共的统计值。输出所有I/O的数据量的合计结果等。
小结
本节使用fio进行实际使用情况的I/O模拟实验,介绍了输出的结果。fio有非常多的选项,可以进行更加精确和详细的设置,由于数量庞大,这里无法一一列举。源代码包含的文档和man中有详细的记载,但都是英文。参考这些内容并熟练使用I/O操作,I/O基准测试就能成为强有力的工具。
—Munehiro IKEDA

相关文章
|
4天前
|
Linux Shell 网络安全
Kali Linux系统Metasploit框架利用 HTA 文件进行渗透测试实验
本指南介绍如何利用 HTA 文件和 Metasploit 框架进行渗透测试。通过创建反向 shell、生成 HTA 文件、设置 HTTP 服务器和发送文件,最终实现对目标系统的控制。适用于教育目的,需合法授权。
28 9
Kali Linux系统Metasploit框架利用 HTA 文件进行渗透测试实验
|
9天前
|
安全 Ubuntu Linux
Metasploit Pro 4.22.6-2024111901 (Linux, Windows) - 专业渗透测试框架
Metasploit Pro 4.22.6-2024111901 (Linux, Windows) - 专业渗透测试框架
32 9
Metasploit Pro 4.22.6-2024111901 (Linux, Windows) - 专业渗透测试框架
|
11天前
|
算法 Linux
深入探索Linux内核的内存管理机制
本文旨在为读者提供对Linux操作系统内核中内存管理机制的深入理解。通过探讨Linux内核如何高效地分配、回收和优化内存资源,我们揭示了这一复杂系统背后的原理及其对系统性能的影响。不同于常规的摘要,本文将直接进入主题,不包含背景信息或研究目的等标准部分,而是专注于技术细节和实际操作。
|
11天前
|
存储 缓存 网络协议
Linux操作系统的内核优化与性能调优####
本文深入探讨了Linux操作系统内核的优化策略与性能调优方法,旨在为系统管理员和高级用户提供一套实用的指南。通过分析内核参数调整、文件系统选择、内存管理及网络配置等关键方面,本文揭示了如何有效提升Linux系统的稳定性和运行效率。不同于常规摘要仅概述内容的做法,本摘要直接指出文章的核心价值——提供具体可行的优化措施,助力读者实现系统性能的飞跃。 ####
|
12天前
|
监控 算法 Linux
Linux内核锁机制深度剖析与实践优化####
本文作为一篇技术性文章,深入探讨了Linux操作系统内核中锁机制的工作原理、类型及其在并发控制中的应用,旨在为开发者提供关于如何有效利用这些工具来提升系统性能和稳定性的见解。不同于常规摘要的概述性质,本文将直接通过具体案例分析,展示在不同场景下选择合适的锁策略对于解决竞争条件、死锁问题的重要性,以及如何根据实际需求调整锁的粒度以达到最佳效果,为读者呈现一份实用性强的实践指南。 ####
|
12天前
|
缓存 监控 网络协议
Linux操作系统的内核优化与实践####
本文旨在探讨Linux操作系统内核的优化策略与实际应用案例,深入分析内核参数调优、编译选项配置及实时性能监控的方法。通过具体实例讲解如何根据不同应用场景调整内核设置,以提升系统性能和稳定性,为系统管理员和技术爱好者提供实用的优化指南。 ####
|
14天前
|
负载均衡 算法 Linux
深入探索Linux内核调度机制:公平与效率的平衡####
本文旨在剖析Linux操作系统内核中的进程调度机制,特别是其如何通过CFS(完全公平调度器)算法实现多任务环境下资源分配的公平性与系统响应速度之间的微妙平衡。不同于传统摘要的概览性质,本文摘要将直接聚焦于CFS的核心原理、设计目标及面临的挑战,为读者揭开Linux高效调度的秘密。 ####
32 3
|
17天前
|
负载均衡 算法 Linux
深入探索Linux内核调度器:公平与效率的平衡####
本文通过剖析Linux内核调度器的工作机制,揭示了其在多任务处理环境中如何实现时间片轮转、优先级调整及完全公平调度算法(CFS),以达到既公平又高效地分配CPU资源的目标。通过对比FIFO和RR等传统调度策略,本文展示了Linux调度器如何在复杂的计算场景下优化性能,为系统设计师和开发者提供了宝贵的设计思路。 ####
31 6
|
17天前
|
消息中间件 安全 Linux
深入探索Linux操作系统的内核机制
本文旨在为读者提供一个关于Linux操作系统内核机制的全面解析。通过探讨Linux内核的设计哲学、核心组件、以及其如何高效地管理硬件资源和系统操作,本文揭示了Linux之所以成为众多开发者和组织首选操作系统的原因。不同于常规摘要,此处我们不涉及具体代码或技术细节,而是从宏观的角度审视Linux内核的架构和功能,为对Linux感兴趣的读者提供一个高层次的理解框架。
|
18天前
|
缓存 网络协议 Linux
深入探索Linux操作系统的内核优化策略####
本文旨在探讨Linux操作系统内核的优化方法,通过分析当前主流的几种内核优化技术,结合具体案例,阐述如何有效提升系统性能与稳定性。文章首先概述了Linux内核的基本结构,随后详细解析了内核优化的必要性及常用手段,包括编译优化、内核参数调整、内存管理优化等,最后通过实例展示了这些优化技巧在实际场景中的应用效果,为读者提供了一套实用的Linux内核优化指南。 ####
43 1