GPUDirect SQL on NFS-over-RDMAを試す

タイトルでほぼほぼ出オチですが、先日、NVIDIAからCUDA Toolkit 11.4と共にリリースされた新機能GPUDirect Storage 1.0のドキュメントを読んでいると、面白い記述を見つけた。

曰く、MOFEDドライバ5.3以降と、Mellanox Connect-X4/5の組み合わせで、NFS-over-RDMAとGPUDirect Storageを組み合わせ、リモートのNFS区画からローカルのGPUへと直接のデータ転送を行う事ができるようになる、と。

14.10. NFS Support with GPUDirect Storage
This section provides information about NFS support with GDS.

14.10.2. Install GPUDirect Storage Support for the NFS Client
Here is some information about installing GDS support for the NFS client.
To install a NFS client with GDS support complete the following steps:
Note: The client must have a Mellanox connect-X4/5 NIC with MLNX_OFED 5.3 or later installed.
:

結構な事である。
PG-Strom v3.0以前では、ローカルのNVME-SSDまたはリモートのNVME-oF区画(実験的)を Ext4 ファイルシステムで初期化したパターンに限って GPUDirect SQL が対応していたため、

  • 段階的にストレージを拡張するのに困難を伴った。
  • 共有ファイルシステムではないので、複数台のノードから書き込みができなかった。

という課題があった。NFS自体はものすごく高速なファイルシステム、というワケではないが、DB/GPUサーバからストレージを分離し、かつ複数のノードから書き込みができるのであれば、例えば、IoT/M2M系のワークロードでログデータを収集し、これをNFSサーバ上に置いておきさえすれば、DB/GPUサーバからこれを参照してGPUDirect SQLの処理スピードでもってコレを分析する事ができる。


結論:結構イケてる

セットアップ手順などは長くなるので後回しにするとして、ひとまずSSBM (Star Schema Benchmark) の結果を一言でまとめると「結構イケてる」という印象。

測定環境は以下の図の通りで、今回は1UサーバのSYS-1019GP-TTにNFSサーバになってもらった。この人には、エンクロージャ経由でNVME-SSDIntel DC P4510[1.0TB; U.2])を4台接続し、また Mellanox Connect-X5 という100Gb-NIC を接続している。
GPU/DBサーバには4UのSYS-4029GP-TRTを使い、この人には、同じPCI-Eスイッチの配下にGPUとConnect-X5を接続したペアと、もう一つGPUとNVME-SSD(同 DC P4510)を4台接続したペアを作った。これはローカルNVME-SSDとの性能比較用である。

NFSサーバは、SSD x4台をmd-raid0でストライピングした区画をNFSクライアントにエクスポートし、NFSクライアントは直結の100Gbネットワーク*1を介して、これをNFS-over-RDMAモードでマウント。

GPU/DBサーバ側では以下のようなストレージ構成となっている。
/opt/nvme0には、ローカルのNVME-SSD x4台をmd-raid0でストライピングした区画をマウント、/opt/nvme1には、1Uサーバ(192.168.80.106)のNFS区画が見えている。

[kaigai@kujira ~]$ df -h
Filesystem                   Size  Used Avail Use% Mounted on
devtmpfs                      94G     0   94G   0% /dev
tmpfs                         94G  257M   94G   1% /dev/shm
tmpfs                         94G   19M   94G   1% /run
tmpfs                         94G     0   94G   0% /sys/fs/cgroup
/dev/mapper/vg_disk-root     246G   15G  218G   7% /
/dev/nvme0n1p1               1.8T   35G  1.7T   2% /opt
/dev/md0p1                   3.6T  1.4T  2.1T  41% /opt/nvme0
/dev/sda2                    976M  189M  721M  21% /boot
/dev/mapper/vg_disk-home     393G   24G  349G   7% /home
/dev/sda1                    599M  6.9M  592M   2% /boot/efi
tmpfs                         19G     0   19G   0% /run/user/1000
192.168.80.106:/mnt/nfsroot  2.0T  1.2T  697G  64% /opt/nvme1

で、それぞれの区画に保持されているlineorderテーブルへの参照を含むSSBMクエリの実行速度は以下の通り。
分かりやすいように、(総DBサイズ)÷(クエリ応答時間)で導出した『クエリ処理スループット』で表記している。

見ての通り、ローカルのNVME-SSDに比べるとNFS-over-RDMAは1割程度遅いと*2言えるが、これは、1割程度遅いだけでストレージの拡張性やリモートアクセスといった特性を得られるという事を意味する。

クエリ実行中のストレージからの読み出し速度を見てみても、クエリ実行中の100Gbのネットワークで8.0GB/s強を出せているので、まずまずのパフォーマンスと言える。
なお、ローカルのNVME-SSDの場合、後半で突然読み出し速度が増しで10.0GB/s程度まで増速しているが、これについては現時点で謎である…。


結論

  • PG-StromのGPUDirect SQLNFS-over-RDMAの併用、低コストのログ集積&分析基盤としては結構アリかもよ。
  • ログデータを Apache Arrow 形式で書き込んでおけば、データをインポートする必要すらなくなります。

NFS-over-RDMAのセットアップ手順

NFS-over-RDMAのセットアップ手順は、以下のブログを参考にした…というか、ほとんどそのまま。
https://community.mellanox.com/s/article/howto-configure-nfs-over-rdma--roce-x

ソフトウェアの構成はざっくり以下の通り

  • CentOS 8.3 (kernel-4.18.0-240.22.1.el8_3.x86_64)
  • CUDA Toolkit 11.4 (NVIDIA Driver R470.42.01)
  • MOFED 5.3-1.0.0.1 (RHEL8.3; x86_64)
  • PostgreSQL v13.3 (PG-Strom v3.0-3)

MOFEDOドライバのインストール

まず、MellanoxのサイトからMOFEDドライバの最新版をダウンロードする。

[Version]->[OS Distribution]->[OS Distribution Version]->[Architecture]と選択していくと、バイナリパッケージを含む tgz のパッケージと、ソースコードの tgz パッケージの両方が表示されるので、両方ともダウンロード。実はソースコードも後で使います。

tgzファイルをダウンロードすると、まず GPUDirect Storage のドキュメント通りにドライバのインストールを行う。
途中、不足するパッケージがある場合には、インストールスクリプトがサジェスト通りに`dnf install ...`すればよいので、その通りに進めればMOFEDドライバのインストールは行えるはず。

$ sudo ./mlnxofedinstall --with-nvmf --with-nfsrdma --enable-gds --add-kernel-support
Note: This program will create MLNX_OFED_LINUX TGZ for rhel8.3 under /tmp/MLNX_OFED_LINUX-5.3-1.0.0.1-4.18.0-240.22.1.el8_3.x86_64 directory.
See log file /tmp/MLNX_OFED_LINUX-5.3-1.0.0.1-4.18.0-240.22.1.el8_3.x86_64/mlnx_iso.225746_logs/mlnx_ofed_iso.225746.log

Checking if all needed packages are installed...
Building MLNX_OFED_LINUX RPMS . Please wait...
    :
  <snip>
    :
$ sudo dracut -f
$ sudo shutdown -r now

これを、NFSサーバ側、NFSクライアント側の両方で行い、システムを再起動。

NFSサーバの設定

1UサーバのSYS-1019GP-TT側では、ローカルのNVME-SSDを4本束ねたmd-raid0区画を`/mnt/nfsroot`にマウントしている。
これを以下の手順でNFS-over-RDMA区画としてエクスポートする。

1. IPアドレス他ネットワーク設定

今回は安直に192.168.80.0/24を直結用のネットワークとして使用。
静的に192.168.80.106/24をConnect-X5デバイスに設定し、MTU=9000でNICを有効化しました。

2. /etc/exportsを記述。特にセキュリティとか何も考えてない設定です。

# cat /etc/exports
/mnt/nfsroot *(rw,async,insecure,no_root_squash)

3. RDMA Transport Kernel Moduleをロード。これはMOFEDドライバによって提供されるモジュール。

# modprobe svcrdma
# modinfo svcrdma
filename:       /lib/modules/4.18.0-240.22.1.el8_3.x86_64/extra/mlnx-nfsrdma/svcrdma.ko
version:        2.0.1
license:        Dual BSD/GPL
description:    svcrdma dummy kernel module
author:         Alaa Hleihel
rhelversion:    8.3
srcversion:     F7C50654667EBC6F832D608
depends:        mlx_compat
name:           svcrdma
vermagic:       4.18.0-240.22.1.el8_3.x86_64 SMP mod_unload modversions

4. NFSサーバを起動

# systemctl start nfs-server

5. RDMA転送用のポート番号を設定。一応、任意のポート番号を使用できるが、20049というのがwell-known defaultとのこと。

# echo rdma 20049 > /proc/fs/nfsd/portlist
# cat /proc/fs/nfsd/portlist
rdma 20049
rdma 20049
tcp 2049
tcp 2049

NFSクライアントの設定

1. IPアドレス他ネットワーク設定

サーバー側と同様、静的に192.168.80.108/24をConnect-X5デバイスに設定し、MTU=9000でNICを有効化しました。
ネットワークの有効化が終わったら、pingなどで導通確認。

$ ping 192.168.80.106
PING 192.168.80.106 (192.168.80.106) 56(84) bytes of data.
64 bytes from 192.168.80.106: icmp_seq=1 ttl=64 time=0.178 ms
64 bytes from 192.168.80.106: icmp_seq=2 ttl=64 time=0.197 ms
^C

2. クライアント側のRDMA Transport Kernel Moduleをロード。これもMOFEDドライバに含まれるモジュール。

# modprobe rpcrdma
# modinfo rpcrdma
filename:       /lib/modules/4.18.0-240.22.1.el8_3.x86_64/extra/mlnx-nfsrdma/rpcrdma.ko
alias:          xprtrdma
alias:          svcrdma
license:        Dual BSD/GPL
description:    RPC/RDMA Transport
author:         Open Grid Computing and Network Appliance, Inc.
rhelversion:    8.3
srcversion:     EFB4ED2B09C65AA7DA8D887
depends:        ib_core,sunrpc,mlx_compat,rdma_cm
name:           rpcrdma
vermagic:       4.18.0-240.22.1.el8_3.x86_64 SMP mod_unload modversions

3. 前節でエクスポートしたNFS区画をマウント

# mount -o rdma,port=20049 192.168.80.106:/mnt/nfsroot /opt/nvme1
# df -h
Filesystem                   Size  Used Avail Use% Mounted on
devtmpfs                      94G     0   94G   0% /dev
tmpfs                         94G  257M   94G   1% /dev/shm
tmpfs                         94G   19M   94G   1% /run
tmpfs                         94G     0   94G   0% /sys/fs/cgroup
/dev/mapper/vg_disk-root     246G   15G  218G   7% /
/dev/nvme0n1p1               1.8T   35G  1.7T   2% /opt
/dev/md0p1                   3.6T  1.4T  2.1T  41% /opt/nvme0
/dev/sda2                    976M  189M  721M  21% /boot
/dev/mapper/vg_disk-home     393G   24G  349G   7% /home
/dev/sda1                    599M  6.9M  592M   2% /boot/efi
tmpfs                         19G     0   19G   0% /run/user/1000
192.168.80.106:/mnt/nfsroot  2.0T  1.2T  697G  64% /opt/nvme1

これで準備完了。
導通確認を兼ねて、巨大なファイルの転送を行ってみる。

# dd if=/opt/nvme1/100GB of=/dev/null iflag=direct bs=32M
3106+1 records in
3106+1 records out
104230305696 bytes (104 GB, 97 GiB) copied, 11.8926 s, 8.8 GB/s

これは速い! 8.8GB/s も出ている。

一方、NFS-over-RDMAを使わないパターンだと。

# mount 192.168.80.106:/mnt/nfsroot /mnt/
# dd if=/mnt/100GB of=/dev/null iflag=direct bs=32M
3106+1 records in
3106+1 records out
104230305696 bytes (104 GB, 97 GiB) copied, 32.6171 s, 3.2 GB/s

御意。

GPUDirect StorageでNFS区画⇒GPUへの直接Readを行う

続いて本番。GPUDirect Storageを使って、リモートのNFS区画からGPUへの直接Readを行う。

今現在、NFS区画からGPUDirect Storageによる直接読み出しが可能な状態になっているかどうか、CUDA 11.4に添付のgdscheckというコマンドで確認する事ができる。。。。が、あらら。Unsupportedと表示されている。

# /usr/local/cuda/gds/tools/gdscheck -p
 GDS release version: 1.0.0.82
 nvidia_fs version:  2.7 libcufile version: 2.4
 ============
 ENVIRONMENT:
 ============
 =====================
 DRIVER CONFIGURATION:
 =====================
 NVMe               : Supported
 NVMeOF             : Supported
 SCSI               : Unsupported
 ScaleFlux CSD      : Unsupported
 NVMesh             : Unsupported
 DDN EXAScaler      : Unsupported
 IBM Spectrum Scale : Unsupported
 NFS                : Unsupported
 WekaFS             : Unsupported
 Userspace RDMA     : Unsupported
 --Mellanox PeerDirect : Enabled
 --rdma library        : Not Loaded (libcufile_rdma.so)
 --rdma devices        : Not configured
 --rdma_device_status  : Up: 0 Down: 0
        :

これは2時間くらいかけて調べたところ、どうやら、MOFEDドライバでバイナリ配布されているrpcrdmaモジュールでGPUDirect Storage対応のコードが有効化されないままビルド、配布されてしまっているという事のようである。

MOFEDドライバのソースコードを見てみると、もしCONFIG_GPU_DIRECT_STORAGE=yつきでビルドされているのであれば、/proc/kallsymsnvfs_opsという関数ポインタ表が出現してしかるべきであるのだが、それが出現していない。

# grep nvfs_ops /proc/kallsyms
ffffffffc0c256c0 b nvfs_ops     [nvme_rdma]
ffffffffc00dc718 b nvfs_ops     [nvme]

という事で、当該モジュールを野良ビルドしてみる事にする。
(なお、NVIDIAの開発チームにはエスカレーション済み。Mellanoxへも展開してくれるでしょう。)

ソースコードの tgz には SRPM が含まれているので、rpcrdmaモジュールを含むmlnx-nfsrdmaSRPMを展開し、これにCONFIG_GPU_DIRECT_STORAGE=yを付加してビルドする。

これをinsmodしてみると、rpcrdmaモジュールにもnvfs_opsシンボルがエクスポートされているのがわかる。

$ wget http://www.mellanox.com/downloads/ofed/MLNX_OFED-5.3-1.0.0.1/MLNX_OFED_SRC-5.3-1.0.0.1.tgz
$ tar zxvf MLNX_OFED_SRC-5.3-1.0.0.1.tgz
$ cd MLNX_OFED_SRC-5.3-1.0.0.1
$ rpm2cpio SRPMS/mlnx-nfsrdma-5.3-OFED.5.3.0.3.8.1.src.rpm | cpio -idu
$ tar zxvf mlnx-nfsrdma-5.3.tgz
$ cd mlnx-nfsrdma-5.3
$ make CONFIG_GPU_DIRECT_STORAGE=y
$ sudo insmod rpcrdma.ko
$ sudo grep nvfs_ops /proc/kallsyms
ffffffffc319ddc8 b nvfs_ops     [rpcrdma]
ffffffffc0c256c0 b nvfs_ops     [nvme_rdma]
ffffffffc00dc718 b nvfs_ops     [nvme]

この状態で、再度gdscheckコマンドを実行してみると。

$ /usr/local/cuda/gds/tools/gdscheck -p
 GDS release version: 1.0.0.82
 nvidia_fs version:  2.7 libcufile version: 2.4
 ============
 ENVIRONMENT:
 ============
 =====================
 DRIVER CONFIGURATION:
 =====================
 NVMe               : Supported
 NVMeOF             : Supported
 SCSI               : Unsupported
 ScaleFlux CSD      : Unsupported
 NVMesh             : Unsupported
 DDN EXAScaler      : Unsupported
 IBM Spectrum Scale : Unsupported
 NFS                : Supported
 WekaFS             : Unsupported
 Userspace RDMA     : Unsupported
 --Mellanox PeerDirect : Enabled
 --rdma library        : Not Loaded (libcufile_rdma.so)
 --rdma devices        : Not configured
 --rdma_device_status  : Up: 0 Down: 0
        :

イヤッホゥゥゥゥ!!!

早速、GPUDirect StorageのRaw-I/O性能を測定してみる事にする。

$ /usr/local/cuda/gds/tools/gdsio -x 0 -f /mnt/100GB -d 1 -s 96G -i 16M -w 6
IoType: READ XferType: GPUD Threads: 6 DataSetSize: 63143936/100663296(KiB) IOSize: 16384(KiB) Throughput: 7.642794 GiB/sec, Avg_Latency: 12874.833807 usecs ops: 3854 total_time 7.879154 secs

イヤッホゥゥゥゥ!!!

サーバ機材は有り合わせなので、もしかするとSkylake-SP内蔵のPCI-Eコントローラで詰まっているかも(帯域的にはそんな感じがしないでもない)しれないが、NFSという言葉から受ける印象とはずいぶん違ったレベルのパフォーマンスを出しているように見える。

さて、それでは、最も重要な PG-Strom でGPUDirect SQLを用いた場合のパフォーマンスを計測してみる事にする。
(⇒先頭に戻る)

8/21追記:5.4-1.0.3.0 ドライバでは直ってた

上記、rpcrdmaモジュールがGPUDirect Storage対応でビルドされていなかった問題ですが、本エントリを書いた時点のMOFEDドライバ(5.3-1.0.0.1)ではなく、最新の 5.4-1.0.3.0 を使用すれば GPUDirect Storage 関連の機能を有効にしてビルドされるようです。

ドライバ標準のインストールスクリプトを実行しただけの状態で

[root@magro ~]# modinfo rpcrdma
filename:       /lib/modules/4.18.0-305.12.1.el8_4.x86_64/extra/mlnx-nfsrdma/rpcrdma.ko
alias:          xprtrdma
alias:          svcrdma
license:        Dual BSD/GPL
description:    RPC/RDMA Transport
author:         Open Grid Computing and Network Appliance, Inc.
rhelversion:    8.4
srcversion:     6144CA5B71903B01293DD5F
depends:        ib_core,sunrpc,mlx_compat,rdma_cm
name:           rpcrdma
vermagic:       4.18.0-305.12.1.el8_4.x86_64 SMP mod_unload modversions
[root@magro ~]# modprobe rpcrdma
[root@magro ~]# grep nvfs_ops /proc/kallsyms
ffffffffc0f20dc8 b nvfs_ops     [rpcrdma]
ffffffffc0970700 b nvfs_ops     [nvme_rdma]
ffffffffc02ce718 b nvfs_ops     [nvme]
[root@magro ~]# /usr/local/cuda/gds/tools/gdscheck -p
 GDS release version: 1.0.1.3
 nvidia_fs version:  2.7 libcufile version: 2.4
 ============
 ENVIRONMENT:
 ============
 =====================
 DRIVER CONFIGURATION:
 =====================
 NVMe               : Supported
 NVMeOF             : Supported
 SCSI               : Unsupported
 ScaleFlux CSD      : Unsupported
 NVMesh             : Unsupported
 DDN EXAScaler      : Unsupported
 IBM Spectrum Scale : Unsupported
 NFS                : Supported
 WekaFS             : Unsupported
 Userspace RDMA     : Unsupported
 --Mellanox PeerDirect : Enabled
 --rdma library        : Not Loaded (libcufile_rdma.so)
 --rdma devices        : Not configured
 --rdma_device_status  : Up: 0 Down: 0
 =====================
 CUFILE CONFIGURATION:
 =====================
 properties.use_compat_mode : true
 properties.gds_rdma_write_support : true
 properties.use_poll_mode : false
 properties.poll_mode_max_size_kb : 4
 properties.max_batch_io_timeout_msecs : 5
 properties.max_direct_io_size_kb : 16384
 properties.max_device_cache_size_kb : 131072
 properties.max_device_pinned_mem_size_kb : 33554432
 properties.posix_pool_slab_size_kb : 4 1024 16384
 properties.posix_pool_slab_count : 128 64 32
 properties.rdma_peer_affinity_policy : RoundRobin
 properties.rdma_dynamic_routing : 0
 fs.generic.posix_unaligned_writes : false
 fs.lustre.posix_gds_min_kb: 0
 fs.weka.rdma_write_support: false
 profile.nvtx : false
 profile.cufile_stats : 0
 miscellaneous.api_check_aggressive : false
 =========
 GPU INFO:
 =========
 GPU index 0 Tesla V100-PCIE-16GB bar:1 bar size (MiB):16384 supports GDS
 ==============
 PLATFORM INFO:
 ==============
 IOMMU: disabled
 Platform verification succeeded

*1:100GbのN/Wスイッチて結構高いんです。涙。

*2:Q3_1で逆転している原因については調査中