タイトルでほぼほぼ出オチですが、先日、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-SSD(Intel 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程度まで増速しているが、これについては現時点で謎である…。
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サーバの設定
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/kallsyms
にnvfs_ops
という関数ポインタ表が出現してしかるべきであるのだが、それが出現していない。
# grep nvfs_ops /proc/kallsyms ffffffffc0c256c0 b nvfs_ops [nvme_rdma] ffffffffc00dc718 b nvfs_ops [nvme]
という事で、当該モジュールを野良ビルドしてみる事にする。
(なお、NVIDIAの開発チームにはエスカレーション済み。Mellanoxへも展開してくれるでしょう。)
ソースコードの tgz には SRPM が含まれているので、rpcrdmaモジュールを含むmlnx-nfsrdma
のSRPMを展開し、これに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