本文主要介绍磁盘性能评估的方法,针对用户态驱动Kernel与SPDK中各种IO测试工具的使用方法做出总结。其中fio是一个常用的IO测试工具,可以运行在Linux、Windows等多种系统之上,可以用来测试本地磁盘、网络存储等的性能。为了和SPDK的fio工具相区别,我们称之为内核fio。
SPDK有自己的IO测试工具,包括fio_plugin,perf和bdevperf。SPDK采用异步I/O(Asynchronous I/O)加轮询(Polling)的工作模式,通常与Kernel的异步I/O作为对比。在此,主要介绍通过使用fio评估Kernel异步I/O,SPDK的三种IO测试工具。
一
FIO准备工作
在测试内核fio和SPDK fio_plugin工具之前,我们先准备好环境。
1.
编译fio
首先,下载fio源码,建议至少切换到3.3及以上版本。
git clone https://github.com/axboe/fio
cd fio && git checkout fio-3.3
make
2.
编译SPDK
下载最新的SPDK源码。然后,运行SPDK configure脚本以启用fio(将其指向fio代码库的根)。
git clone https://github.com/spdk/spdk
cd spdk
git submodule update --init
./configure--with-fio=/path/to/fio/repo
(例如:./configure --with-fio=/usr/src/fio)
make
当使用参数--with-fio编译时,我们会发现在
二
内核fio工具测试磁盘性能
典型的fio工作过程:
1)写一个job文件来描述要访真的io负载。一个job文件可以控制产生任意数目的线程和文件。典型的job文件有一个global段(定义共享参数),一个或多个job段(描述具体要产生的job)。
2)运行时,fio从文件读这些参数,做处理,并根据这些参数描述,启动这些线程/进程。
运行fio:
# fio job_file
它会根据job_file的内容来运行。我们可以在命令行中指定多个job file,fio串行化运行这些文件。
Job文件格式:
job file格式采用经典的ini文件,[]中的值表示job name,可以采用任意的ASCII字符。
IO引擎:
ioengine=str
定义job向文件发起IO的方式。使用I/O引擎就是使用某些函数,以某些特定方式来访问存储,Linux可以使用 libaio,sync,psync等。这里只介绍libaio的例子,以用作和下文SPDK的fio_plugin做对比。
libaio,即异步I/O的引擎。这时通常,I/O请求会发送到相应的队列中,等待被处理,因此队列深度将会影响磁盘性能。所以在测试异步I/O的时候,根据磁盘的特性指定相应的队列深度(iodepth)。
一个典型的fio配置文件,nvme_bdev_job.fio:
- [global]
-
- ioengine=libaio
-
- thread=1
-
- group_reporting=1
-
- direct=1
-
- norandommap=1
-
- cpumask=1
-
- bs=4k
-
- rw=randread
-
- iodepth=256
-
- time_based=1
-
- ramp_time=0
-
- runtime=30
-
-
-
- [job]
-
- filename=/dev/nvme0n1
部分参数解释
ioengine:指定I/O引擎,在这里测试Kernel的异步I/O,因此指定I/O引擎为libaio;
direct: 指定direct模式O_DIRECT,I/O会绕过系统的page buffer;
rw:读写模式,这里指定randrw表示混合随机读写;
rwmixread:混合随机读写模式下read请求所占比例;
thread:指定使用线程模式。由于spdk fio_plugin只支持线程模式,因此与Kernel对比时,通常都统一指定线程模式来对比;
norandommap:指定I/O时,每次都获取一个新的随机offset,防止额外的CPU使用消耗;
time_based:指定采用时间模式;
runtime:测试时长,单位是秒;
ramp_time:统计性能之前所运行的时间,为了防止没有进行稳态而造成的性能虚高带来的影响,单位是秒;
bs:I/O块大小;
iodepth:队列深度;
numjobs:worker的个数;
filename:指定测试的对象。
运行fio(带配置文件)举例:
[root@server spdk]# fio nvme_bdev_job.fio
另一种用法,不使用fio文件,直接使用参数
# fio -filename=/dev/nvme0n1 -direct=1 -iodepth 1 -thread -rw=randread \
-ioengine=libaio -bs=4k -size=1G -runtime=10 -group_reporting -name=rand_read_4k
三
SPDK的fio_plugin工具
通常,在内核模式下,使用fio工具来测试设备在实际的工作负载下所能承受的最大压力。用户可以启动多个线程,对设备来模拟各种IO操作,使用filename指定所被测试的设备。然而,在SPDK用户态模式情况下,SPDK在使用前会unbind内核驱动,直接通过PCI地址来识别设备,因此用户在系统上无法直接看到设备。为此,SPDK推出fio_plugin与SPDK深度集成,用户可以通过指定设备的PCI地址,来决定所要进行压力测试的设备。同时,在fio_plugin内部,采用SPDK用户态设备驱动所提供的轮询和异步的方式进行I/O操作,I/O通过SPDK直接写入磁盘。
SPDK提供两种形态的fio_plugin:
•基于裸盘NVMe的fio_plugin,其特点为I/O通过SPDK用户态驱动直接访问裸盘,常用于评估SPDK用户态驱动在裸盘上的性能。
•基于bdev的fio_plugin,其特点为I/O测试基于SPDK块设备bdev之上,所有I/O经由块设备层bdev,再传送至裸盘设备。常用于评估SPDK块设备bdev的性能。
1.
基于NVMe的fio_plugin
前提条件
按照第一章节步骤,下载好内核fio和SPDK代码并编译。
测试方法
a. 使用fio_plugin测试裸盘,需要引入fio_plugin路径,因此在运行fio时,在fio命令之前加如下参数:
export LD_PRELOAD (只需要一遍)
LD_PRELOAD=
(如果解除,用unset LD_PRELOAD )
也可以export LD_PRELOAD=spdk/examples/… 写成一句
b. 其次,需要在fio配置文件中设定ioengine为spdk。
ioengine=spdk
c. 运行fio_plugin时,同时要通过额外的参数'--filename'指定SPDK能够识别的设备地址信息。
但是,NVMe的fio_plugin配置文件里不需要指定spdk_json_conf。
通常,NVMe的fio_plugin支持两种模式下的测试,
一是本地的NVMe设备,即NVMe over PCIe;
二是远端的NVMe设备,即NVMe over Fabrics。
运行,NVMe over PCIe:
[root@server spdk]# LD_PRELOAD=build/fio/spdk_nvme /usr/src/fio/fio \
spdk_nvme1.fio '--filename=trtype=PCIe traddr=0000.06.00.0 ns=1'
在initiator端执行NVMe over Fabrics(transport=RDMA):
[root@server2 spdk]# LD_PRELOAD=build/fio/spdk_nvme \
/usr/src/fio/fio spdk_nvme1.fio \
'--filename=trtype=RDMA adrfam=IPv4 traddr=192.168.100.8 trsvcid=4420 ns=1'
或者,在initiator端执行NVMe over Fabrics(transport=TCP):
[root@server2 spdk]# LD_PRELOAD=build/fio/spdk_nvme \
/usr/src/fio/fio spdk_nvme1.fio \
'--filename=trtype=TCP adrfam=IPv4 traddr=192.168.100.8 trsvcid=4420 ns=1'