一文评估基于SPDK的NVMe SSD性能

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

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

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

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配置参数示例如下:

[Global]

参数详解

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:

git clone https : //github . com/axboe/fio

b.下载编译SPDK:

git clone https : //github . com/spdk/spdk

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

测试方法

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

LD_PRELOAD=/examples/nvme/fio_plugin/fio_plugin

b. 其次,需要在fio配置文件中设定ioengine为spdk。

c. 运行fio时候,不仅要指定fio运行配置文件,同时要通过额外的参数'--filename'指定spdk能够识别的设备地址信息。通常,fio_plugin支

NVMe over PCIe:

其它说明

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

LD_PRELOAD=.../fio_plugin fio config.fio '--filename=trtype=PCIe traddr=0000.06.00.0 ns=1' '--filename=trtype=PCIe traddr=

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

LD_PRELOAD.../fio_plugin fio --enghelp=spdk

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'即可测试。

3. 基于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命令之前加如下参数:

LD_PRELOAD=/examples/bdev/fio_plugin/fio_plugin

b. 其次,需要在fio配置文件中设定ioengine为spdk_bdev

c. 需要在fio配置文件中指定spdk启动配置文件。如下所示:

spdk_conf=./example/bdev/fio_plugin/bdev.conf

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

[Malloc]
        NumberOfLuns 1
[Nvme]
        TransportID "trtype:PCIe traddr:0000:82:00.0" Nvme0
        RetryCount 4

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

LD_PRELOAD=.../fio_plugin fio config.fio '--filename=Nvme0n1'

其他说明

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

LD_PRELOAD=.../fio_plugin fio config.fio '--filename=Nvme0n1' '--filename=Malloc0'

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

LD_PRELOAD.../fio_plugin fio --enghelp=spdk_bdev

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 -c  -q  -t 

perf支持本地的NVMe设备,同时也支持远端的NVMeoF的设备。使用范例如下:

NVMe over PCIe:

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

perf -q 32 -s 1024 -w randwrite -t 1200 -c 0x1 -o 4096 -r 'trtype:PCIe traddr:0000:06:00.0' -r 'trtype:PCIe

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

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

perf -q 32 -s 1024 -w randwrite -t 1200 -c 0xF -o 4096 /dev/nvme0n1

3. 基于bdev的perf工具

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

bdevperf -c  -q  -t 

其中,-c是指定bdevperf的配置文件,需要测试的bdev设备都在配置文件中指定,例如,若需要测试本地的两块NVMe设备,则bdevperf的配置文

[Nvme]

        TransportID "trtype:PCIe traddr:0000:82:00.0"         Nvme0

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

bdevperf -q 32 -s 1024 -w randwrite -t 1200 -o 4096 -m 0xF -c bdevperf.conf

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

[Nvme]

        TransportID "trtype:PCIe traddr:0000:82:00.0" Nvme0
        TransportID "trtype:PCIe traddr:0000:83:00.0" Nvme1

三. 常见问题

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不再增长。

       下面给出各种硬盘建议的评估参数:Intel P3700: numjob=1, iodepth=128

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。这时测得的性能为裸盘的性能 。

原文链接:https://blog.csdn.net/weixin_37097605/article/details/101514541

你可能感兴趣的:(网络,服务器,linux,网络协议,java)