基于SPDK的NVMe SSD性能评估指南

原文地址:DPDK与SPDK开源社区
作者简介:周雁波,存储软件工程师,从事SPDK的开发与性能测试工作。

本文主要介绍磁盘性能评估的方法,针对用户态驱动SPDK与Kernel,并且对常见问题做出总结。

一 通过fio工具测试磁盘性能

SPDK采用异步I/O(Asynchronous I/O)加轮询(Polling)的工作模式,通常与Kernel的异步I/O作为对比。在此,主要介绍通过使用fio评估Kernel异步I/O,以及spdk fio_plugin的两种模式。

1、fio评估kernel异步I/O(AIO)

fio支持多种模式的I/O引擎,同时也包含了测试异步I/O的引擎,即libaio。在测试异步I/O的时候,只需要将fio启动配置文件中的ioengine设为libaio即可。通常在做异步I/O的时候,I/O请求会发送到相应的队列中,等待被处理,因此队列深度将会影响磁盘性能。所以在测试异步I/O的时候,根据磁盘的特性指定相应的队列深度(iodepth)。
测试Kernel异步I/O的fio配置参数示例如下:

参数详解

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:指定测试的对象。

2、基于NVMe的fio_plugin

安装步骤

a. 下载编译fio:

b.下载编译SPDK:

注意:由于fio_plugin要依赖fio中提供的一些依赖包,因此在运行configure时,必须指定fio目录,否则默认fio_plugin不会编译

测试方法

a. 使用fio_plugin测试裸盘,需要引入fio_plugin路径,因此在运行fio时,在fio命令之前加如下参数:

b. 其次,需要在fio配置文件中设定ioengine为spdk。
c. 运行fio时候,不仅要指定fio运行配置文件,同时要通过额外的参数’–filename’指定spdk能够识别的设备地址信息。通常,fio_plugin支
持两种模式下的测试,一是本地的NVMe设备,即NVMe over PCIe;二是远端的NVMe设备,即NVMe over Fabrics。如下所示:

其它说明

a. 对于使用1个core,测试多块盘的情况,通常只需要设定numjob为1,同时在fio命令通过多个filename参数来指定多块要测试的盘(多个filename参数之间用空格相隔即可),例如同时测试三块盘:

b. 对于使用fio_plugin作为新的ioengine而引入的新的fio参数说明,可以通过以下命令查看相关参数说明:

c. 此外,可以通过直接在ioengine中指定fio_plugin的绝对路径,而无须每次运行fio都动态加载LD_PRELOAD。即: fio配置文件中添加修改ioengine=/examples/nvme/fio_plugin/fio_plugin;运行fio config.fio ‘–filename=trtype=PCIe traddr=0000.06.00.0 ns=1’即可测试。

基于bdev的fio_plugin

基于bdev的fio_plugin是将I/O在spdk块设备bdev之上进行发送。而基于裸盘的fio_plugin,I/O是直接到裸盘上进行处理。因此两者最大的差别在于I/O是否经过bdev这一层。因此,基于bdev的fio_plugin能够很好的评估spdk块设备层bdev的性能。
其编译安装与裸盘的fio_plugin完全相同,下面详细介绍其测试方法:
a. 使用fio_plugin测试bdev性能,需要bdev fio_plugin的路径,因此在运行fio时,在fio命令之前加如下参数:

b. 其次,需要在fio配置文件中设定ioengine为spdk_bdev
c. 需要在fio配置文件中指定spdk启动配置文件。如下所示:

spdk运行配置文件中指定了所有bdev的配置信息,示例如下:

d.运行fio的时候,通过’–filename’直接指定所要测试的bdev名称即可,示例如下:

其他说明

a. 使用基于bdev的fio_plugin测试多个设备时候,需要在spdk运行配置文件中写入相应的bdev配置信息,其次在fio运行时,指定多个filename参数即可,多个filename之间用空格相隔。例如同时测两个设备Malloc0与Nvme0n1,如下所示:

b.同理,若查看基于bdev的fio_plugin相关参数说明,可以通过如下命令:

c. 此外,可以通过直接在ioengine中指定fio_plugin的绝对路径,而无须每次运行fio都动态加载LD_PRELOAD。即:
fio配置文件中添加修改ioengine=/examples/bdev/fio_plugin/fio_plugin;运行fio config.fio ‘–filename=Nvme0n1’即可测试。

二 通过spdk perf测试磁盘性能

1、基于NVMe的perf工具

成功编译spdk后,可在spdk/examples/nvme/perf/目录下找到perf工具的二进制运行文件。perf使用方法如下所示:

更多参数解析,请参考perf –help
perf支持本地的NVMe设备,同时也支持远端的NVMeoF的设备。使用范例如下:

对于同时测试多块盘,只需要添加-r并指定设备地址即可,例如一个core测试三块盘:

2、perf评估Linux异步I/O(AIO)

使用方式与测试spdkdriver相同,只需要在perf命令后添加设备名称即可。使用范例如下:

3、基于bdev的perf工具

成功编译spdk后,可在spdk/test/bdev/bdevperf/目录下找到bdevperf工具的二进制运行文件。bdevperf使用方法如下所示:

更多参数解析,请参考perf –help。
其中,-c是指定bdevperf的配置文件,需要测试的bdev设备都在配置文件中指定,例如,若需要测试本地的两块NVMe设备,则bdevperf的配置文
件示例如下:

相应的bdevperf启动参数示例如下:

对于bdevperf,若要测试多块盘,则只需要在spdk配置文件中配置多块盘的信息即可,例如同时测试三块盘:

三 常见问题

1

通过fio与perf对SPDK进行性能评估,得到的结果不同,大部分的时候perf所得到的性能会比fio所得到的性能要高。
两种工具最大的差别在于,fio是通过与Linux fio工具进行集成,使其可以用fio_plugin引擎测试SPDK设备。而由于fio本身架构的问题,不能充分发挥SPDK的优势,整个应用框架仍然使用fio原本的架构。例如fio使用Linux的线程模型,在使用的时候,线程仍然被内核调度。而对于perf来说,是针对SPDK所设计的性能测试工具,因此在底层,不仅是I/O通过SPDK下发,同时一些底层应用框架都是为SPDK所设计的。例如刚刚所提到的线程模型,perf中是使用DPDK所提供的线程模型,通过使用CPU的亲和性将CPU核与线程捆绑,不再受内核调度,因此可以充分发挥SPDK下发I/O时的异步无锁化优势。这就是为什么perf所测得的性能要比fio高,尤其是在使用单个线程(单核)同时测试多块盘的情况下,fio所得性能要明显小于perf所得性能。因此,在同等情况下,我们更推荐用户使用perf工具对SPDK进行性能评估。
此外,在多numjob的情况下,fio与perf对iodepth的分配是不同的。通常在fio中,指定的iodepth表示所有的job一共的iodepth,而在perf指定的iodepth(perf中-q参数)通常指的是每个job所使用的iodepth。举例如下:Fio:numjob=4, iodepth=128。则每个job对应的iodepth为32(128/4)。Perf:-c 0xF (相当于fio中numjob=4),-q 128(相当于fio中iodepth=128)。则每个job对应的iodepth为128。

2

对SPDK和内核的性能评估时,虽然性能有所提升,但是没有看到SPDK官方所展示的特别大的性能差异。
首先,如问题1中所述,不同的工具之间所得出的性能结果是不同的,另外最主要的因素还是硬盘本身的性能瓶颈所导致的问题。例如,以2D NAND为介质的Intel DC P3700,本身的性能都存在一定的瓶颈,因此无论是SPDK用户态驱动还是内核驱动,都不会达到较高的IOPS。若换用更高性能的硬盘,例如使用以3D Xpoint为介质的Optane(Intel DC P4800X)为测试对象,便会看到很大的性能差异。因此,硬盘性能越高,SPDK所发挥出的优势越明显,这也是SPDK产生的初衷,其本身就是为高性能硬盘所订制的。

3

关于评估不同硬盘的队列深度(iodepth)与CPU core的问题。
通常根据不同硬盘的特点,选择不同的iodepth以及所使用的CPUcore。通常在评估以2D NAND、3D NAND介质的硬盘,一般情况下,为了达到磁盘的最高性能,通常会选择较高的iodepth(128或256)。对于P4XXX的硬盘,通常可能一个CPU core无法达到满IOPS,此时并不是由于一个core的能力不够,而是由于硬盘中硬件队列本身限制的问题。因此,通常需要使用两个CPU core才能够达到specification中的满IOPS。此外,对于以3D Xpoint为介质的Optane(Intel P4800X),通常只需要一个core并使用较小的iodepth即可达到满IOPS,此时已经达到硬盘的上限,若再次增大iodepth只会是latency变大而IOPS不再增长。
下面给出各种硬盘建议的评估参数:

4

关于写性能虚高的问题。
通常以2D NAND、3D NAND为介质的硬盘,在测试write/randwrite的性能时候,通常要比sepcification里的最高值高很多。这是由于这类介质本身的问题,所以在测试时会出现write/randwrite性能虚高的问题。因此在测试该类硬盘,为了避免此类现象,通常需要对磁盘做一次precondition。通常的做法为:在格式化之后,对磁盘不断进行写操作,写满整个磁盘,使其进行稳态。以DC P3700 800GB为例,通常首先以4KB的大小顺序写两小时,之后再随机写一小时。此外,在测试的时候,fio参数中的ramp_time可以设置较大一些,避免初始的虚高值计入最终结果。

5

关于磁盘性能测试指标。
通常,对于一个磁盘的性能,我们主要从三方面去评估:IOPS、bandwidth、latency。
IOPS:通常评估磁盘的IOPS,主要关注块大小为4k,随机读写的情况。因此,通常fio关键参数为:bs=4k,iodepth=128,direct=1,rw=randread/randwrite。
Bandwidth:评估磁盘的bandwidth,通常是关注块大小为128k,顺序读写的情况。因此,通常fio关键参数为:bs=128k,iodepth=128,direct=1,rw=read/write。
Latency:评估latency通常情况下,是关注一个I/O发送/完成的延迟情况,因此,通常选择iodepth为1。因此,通常fio关键参数为:bs=4k,iodepth=1,direct=1,rw=randread/randwrite。此外,对于latency的结果,不仅要关注平均值,同时也要注意长尾延迟,即99.99%的延迟情况。
注意:通常在测试磁盘的性能时,要添加direct=1,即绕过系统的cache buffer。这时测得的性能为裸盘的性能 。

“基于SPDK的NVMe SSD性能评估指南” 包含 1 条回应

  1. 周雁波老师,您好!请教问题如下:
    我在perf测试完SPDK后,使用perf测试linux AIO时,我先使用sudo scripts/setup.sh reset将设备rebind到内核了,测试成功返回了结果,但是我用perf测试SPDK和linux AIO得到的IOPS始终差不多大,只是SPDK的延时会小很多。
    测试命令和您博客的一样,perf -q 32 -s 1024 -w randwrite -t 1200 -c 0xF -o 4096 -r ‘trtype:PCIe traddr:0000:06:00.0’,对应的需要替换成我设备的比如traddr等都替换了,测试出来了结果。
    设备是:英特尔(Intel)Optane傲腾900P 280G PCI-E NVME SSD
    我想请教为什么perf测试出来的SPDK和linux AIO的IOPS始终差不多大小,qd我测了4/8/16/32/64/128,perf测试SPDK得到的IOPS和设备标称的最大IOPS一样,这个感觉没问题,但是perf测试出来的LinuxAIO的IOPS也是这么大,我就感觉很疑惑。
    谢谢您!
    祝好。

发表评论

电子邮件地址不会被公开。 必填项已用*标注