目次
概要
前回、NVMe over RDMA 環境を構築し、簡単な動作確認を行いました。
今回は、前回の概要でも触れたとおりNVMe over TCP を試してみます。
NVMe over TCP はその名の通り、NVMe プロトコルを TCP プロトコル上に流すことでリモートでの利用を可能にしたものです。
NVMe over RDMA (RoCEv2) と異なり、一般的な TCP プロトコルを使用しているため専用のスイッチなどを必要としないメリットがあります。
しかしながら、メモリ上のデータを直接扱う RDMA の恩恵を受けられないため、プロトコルスタックの処理によるCPU負荷の上昇やIOに対する遅延の増大、スループットの低下などのデメリットも存在します。
今回はそんな NVME over TCP 環境を構築し、動作確認を行ってみます。
環境
今回の検証に使用した環境です。
マシンは2台用意し、それぞれをターゲット(Server)側、Initiator(Client)側としています。
ターゲット側
詳細 | |
---|---|
Machine | HPE ProLiant DL380 Gen10 |
CPU | Intel Xeon Silver 4208 x2 |
Memory | DDR4 ECC RDIMM 128GB (16GB x8 2400MHz) |
NIC | Mellanox ConnectX-4 100Gb(Ethernet) MCX415A-CCAT |
NVMe | Intel DC P4600 1.6TB U.2 x2 |
OS | Ubuntu Server 22.04 LTS |
Initiator側
詳細 | |
---|---|
Machine | Fujitsu Primergy RX2540 M4 |
CPU | Intel Xeon Gold 6148 x1 |
Memory | DDR4 ECC RDIMM 128GB (32GB x4 2666MHz) |
NIC | Mellanox ConnectX-4 100Gb(Ethernet) MCX415A-CCAT |
OS | Ubuntu Server 22.04 LTS |
準備
今回も、前回と同様に SPDK を用いて環境構築を行います。
SPDK をビルドし nvmf_tgt
が実行可能な状態までは前回と同様の手順です。
ネットワーク設定
この段階でネットワーク設定を行っておきます。
手順については省略します。
なお、今回は次のような構成にしています。
なお、リンクスピードは100Gbps、MTUは9000です。
ターゲット側 10.0.0.1/24 ---------- 10.0.0.2/24 Initiator側
nvme-cliのインストール
ターゲット側とInitiator側の両方に nvme-cli をインストールしておきます。
# apt install nvme-cli
ターゲット側の設定
nvmf_tgt
を起動した状態で設定を入れていきます。
前回と異なるのは、 nvmf_create_transport
と nvmf_subsystem_add_listener
設定において TCP を指定している部分です。
root@target:~/spdk# ./build/bin/nvmf_tgt
root@target:/usr/src/spdk# ./scripts/rpc.py nvmf_create_transport -t TCP -u 16384 -m 8 -c 8192
root@target:/usr/src/spdk# scripts/rpc.py bdev_nvme_attach_controller -b NVMe0 -a 0000:39:00.0 -t pcie
NVMe0n1
root@target:/usr/src/spdk# scripts/rpc.py bdev_nvme_get_controllers
[
{
"name": "NVMe0",
"ctrlrs": [
{
"state": "enabled",
"trid": {
"trtype": "PCIe",
"traddr": "0000:39:00.0"
},
"cntlid": 0,
"host": {
"nqn": "nqn.2014-08.org.nvmexpress:uuid:d4549310-b740-4edc-bed0-95dbcbec1178",
"addr": "",
"svcid": ""
}
}
]
}
]
root@target:/usr/src/spdk# scripts/rpc.py nvmf_create_subsystem nqn.2016-06.io.spdk:cnode1 -a -s SPDK00000000000001 -d SPDK_Controller1
root@target:/usr/src/spdk# scripts/rpc.py nvmf_subsystem_add_ns nqn.2016-06.io.spdk:cnode1 NVMe0n1
root@target:/usr/src/spdk# scripts/rpc.py nvmf_subsystem_add_listener nqn.2016-06.io.spdk:cnode1 -t tcp -a 10.0.0.1 -s 4420
なお、詳細な設定内容や複数ディスクへの対応方法などは前回の記事で解説しています。
Initiator側の設定
NVMe over TCP を利用するには nvme-tcp モジュールが必要となり、対応したカーネルに更新する必要があります。
今回は、 linux-modules-extra-5.15.0-1004-gke
を利用します。
root@initiator:# apt install linux-modules-extra-5.15.0-1004-gke
root@initiator:# reboot
root@initiator:# mobprobe nvme_tcp
無事に nvme-tcp モジュールを有効化出来たら、nvme discover
を実行して検出できるか確認します。
root@initiator:~# nvme discover -t tcp -a 10.0.0.1 -s 4420
Discovery Log Number of Records 1, Generation counter 1
=====Discovery Log Entry 0======
trtype: tcp
adrfam: ipv4
subtype: nvme subsystem
treq: not required
portid: 0
trsvcid: 4420
subnqn: nqn.2016-06.io.spdk:cnode1
traddr: 10.0.0.1
sectype: none
接続し、認識しているか確認します。
root@initiator:~# nvme connect -t tcp -n "nqn.2016-06.io.spdk:cnode1" -a 10.0.0.1 -s 4420
root@initiator:~# nvme list
Node SN Model Namespace Usage Format FW Rev
--------------------- -------------------- ---------------------------------------- --------- -------------------------- ---------------- --------
/dev/nvme0n1 SPDK00000000000001 SPDK_Controller1 1 1.60 TB / 1.60 TB 512 B + 0 B 22.09
問題なく認識していることが確認できたので、 fio で簡単にベンチマークしていきます。
fioを用いてベンチマーク
Initiator 側から NVMe に IO 負荷をかけてベンチマークを実施します。
ベンチマークには fio を用います。
root@initiator:~# apt install fio
シーケンシャルリードでベンチマークをまわしてみます。
root@initiator:~# fio --name=seqread --rw=read --filename=/dev/nvme0n1 --direct=1 --ioengine=libaio --bs=32m --numjobs=2 --size=10G --group_reporting
seqread: (g=0): rw=read, bs=(R) 32.0MiB-32.0MiB, (W) 32.0MiB-32.0MiB, (T) 32.0MiB-32.0MiB, ioengine=libaio, iodepth=1
...
fio-3.28
Starting 2 processes
Jobs: 2 (f=2): [R(2)][100.0%][r=3171MiB/s][r=99 IOPS][eta 00m:00s]
seqread: (groupid=0, jobs=2): err= 0: pid=2327: Fri Jul 1 13:32:00 2022
read: IOPS=98, BW=3167MiB/s (3321MB/s)(20.0GiB/6466msec)
slat (usec): min=6780, max=27344, avg=12248.84, stdev=2025.29
clat (usec): min=5220, max=12290, avg=7910.04, stdev=1526.57
lat (usec): min=15432, max=35796, avg=20160.18, stdev=1641.21
clat percentiles (usec):
| 1.00th=[ 5342], 5.00th=[ 5538], 10.00th=[ 5735], 20.00th=[ 6128],
| 30.00th=[ 6718], 40.00th=[ 7504], 50.00th=[ 8291], 60.00th=[ 8717],
| 70.00th=[ 8979], 80.00th=[ 9241], 90.00th=[ 9634], 95.00th=[10028],
| 99.00th=[10552], 99.50th=[10814], 99.90th=[12256], 99.95th=[12256],
| 99.99th=[12256]
bw ( MiB/s): min= 3008, max= 3328, per=100.00%, avg=3173.33, stdev=42.02, samples=24
iops : min= 94, max= 104, avg=99.17, stdev= 1.31, samples=24
lat (msec) : 10=94.06%, 20=5.94%
cpu : usr=0.28%, sys=7.61%, ctx=11290, majf=0, minf=16410
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 rwts: total=640,0,0,0 short=0,0,0,0 dropped=0,0,0,0
latency : target=0, window=0, percentile=100.00%, depth=1
Run status group 0 (all jobs):
READ: bw=3167MiB/s (3321MB/s), 3167MiB/s-3167MiB/s (3321MB/s-3321MB/s), io=20.0GiB (21.5GB), run=6466-6466msec
Disk stats (read/write):
nvme0n1: ios=0/0, merge=0/0, ticks=0/0, in_queue=0, util=0.00%
3.3GB/s
となっており、これは使用したNVMeの公称値とほぼ同様です。
続いて、シーケンシャルライトを試します。
root@initiator:~# fio --name=seqwrite --rw=write --filename=/dev/nvme0n1 --direct=1 --ioengine=libaio --bs=32m --numjobs=2 --size=10G --group_reporting
seqwrite: (g=0): rw=write, bs=(R) 32.0MiB-32.0MiB, (W) 32.0MiB-32.0MiB, (T) 32.0MiB-32.0MiB, ioengine=libaio, iodepth=1
...
fio-3.28
Starting 2 processes
Jobs: 2 (f=2): [W(2)][100.0%][w=1280MiB/s][w=40 IOPS][eta 00m:00s]
seqwrite: (groupid=0, jobs=2): err= 0: pid=2372: Fri Jul 1 13:32:35 2022
write: IOPS=38, BW=1248MiB/s (1308MB/s)(20.0GiB/16414msec); 0 zone resets
slat (usec): min=7971, max=51897, avg=27101.64, stdev=4912.11
clat (usec): min=10756, max=46502, avg=24141.04, stdev=5077.53
lat (usec): min=25093, max=79939, avg=51243.83, stdev=6243.81
clat percentiles (usec):
| 1.00th=[14484], 5.00th=[16909], 10.00th=[18482], 20.00th=[20055],
| 30.00th=[21103], 40.00th=[22676], 50.00th=[23725], 60.00th=[24773],
| 70.00th=[25822], 80.00th=[27395], 90.00th=[31065], 95.00th=[33817],
| 99.00th=[39584], 99.50th=[40633], 99.90th=[46400], 99.95th=[46400],
| 99.99th=[46400]
bw ( MiB/s): min= 960, max= 1408, per=99.86%, avg=1246.00, stdev=60.59, samples=64
iops : min= 30, max= 44, avg=38.94, stdev= 1.89, samples=64
lat (msec) : 20=19.69%, 50=80.31%
cpu : usr=3.62%, sys=4.22%, ctx=11075, majf=0, minf=19
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 rwts: total=0,640,0,0 short=0,0,0,0 dropped=0,0,0,0
latency : target=0, window=0, percentile=100.00%, depth=1
Run status group 0 (all jobs):
WRITE: bw=1248MiB/s (1308MB/s), 1248MiB/s-1248MiB/s (1308MB/s-1308MB/s), io=20.0GiB (21.5GB), run=16414-16414msec
Disk stats (read/write):
nvme0n1: ios=0/0, merge=0/0, ticks=0/0, in_queue=0, util=0.00%
こちらも 1.3GB/s
となっており公称値と同等です。
まとめ
今回は、前回作成した環境と SPDK を利用して、NVMe over TCP 環境を構築し、簡単なパフォーマンス測定を行いました。
シーケンシャルリード/ライトにおいてはスループット面では特に問題はないようです。
次回、NVMe over RDMA と NVMe over TCP の詳細なパフォーマンス測定を行う予定です。