スキャン速度10GB/sへの挑戦~その④ 完結編~

今回のエントリは、ここ1年ほど取り組んでいた PG-Strom による大量データのスキャン・集計処理性能改善の取り組みが、当面の目標であったシングルノード10GB/sを達成したという完結編です。(長かった)

要素技術:SSD-to-GPUダイレクトSQL

先ず、PG-Stromのストレージ関連機能について軽くおさらい。

RDBMSに限らず一般論として、GPUなど並列プロセッサの処理性能を稼ぐには、プロセッサコアの数や動作クロック以上に、処理すべきデータをできるだけ大量に供給するかという点が重要。
これは、ハードウェアレベルではキャッシュ階層や容量の設計、あるいはメモリデバイスのデータ転送レートという話になり、最近のGPUだとメモリ読出しの帯域は数百GB/sにも達する。もう少し大局的に見ると、これは、ストレージと計算機をどのように接続し、アプリケーションはこれをどのように制御するのかという話になってくる。

PG-Stromは元々、PostgreSQLのストレージ層をそのまま利用していた。これは業務系⇒情報系の間でデータ形式を変更するのがユーザにとって手間であり、使い勝手を損なうと考えたため。ただこれは、処理がI/O待ちになった瞬間、GPUによる高速化の効果を全て打ち消してしまったため、当時は『データを前もってメモリにロードしておいて下さい』と言っていた。
しかし、同じストレージ上のデータを使いつつも、読み出す方法を変える事でI/Oを高速化できるのであれば、使い勝手とGPUによる高速化は矛盾しない。
現在のPG-Stromはいくつかのストレージ機能強化を持っているが、その最も特徴的な機能である「SSD-to-GPUダイレクトSQL」は、ストレージに格納せざるを得ないサイズのデータをGPUのプロセッサへ高速に供給するための機能である。

テーブルの全件スキャンが必要な集計系クエリを実行する場合、通常、ストレージ上のPostgreSQLデータブロックをホストRAMにロードし、その後で、このレコードは条件句に合う、合わないといった処理を行う。
そのため、最終的には破棄する事になる「ゴミデータ」も含めて帯域の限られたPCIeバスを転送しなければならない。また、単にPCIeバスの帯域だけでなく、ホストシステムのDMAバッファ→Page Cache→PostgreSQLのShared Bufferというメモリコピーの負荷も馬鹿にならない。

一方、SSD-to-GPUダイレクトSQLの場合、P2P DMAを用いてストレージ(NVME-SSD)上のデータブロックをP2P DMAを用いてGPUへ転送する。このデータ転送にホストRAMは介在しない。次にGPU上でWHERE句/JOIN/GROUP BYといった集計系クエリの中核となる処理を実行する。ワークロードとデータの分布次第ではあるが、基本的にこれらの処理は不要レコードを落とし、予め集計を済ませておく事でデータ量を削減する事が可能である。
したがって、前処理済みのデータがホストRAMへロードされた時点でデータ量が1/1000以下になっているという事も珍しくない。

パフォーマンスは良好。少し古い計測データだが、1枚あたり2.2GB/sのSeqRead性能を持つIntel SSD 750 (400GBl HHHL) を3枚束ねた構成で、ハードウェア的な限界性能6.6GB/sに対し、Star Schema Benchmark (SSBM) の実行性能で6.3GB/sまで出ている事が分かる。

PCIeバスの最適化を考える

GPUの処理能力にはまだ余裕があったため、次に考えたのは、より高速なSSDを使用する事で処理速度を引き上げられないだろうかという目論見。これは部分的には成功するが、課題も残す。
kaigai.hatenablog.com

NVIDIAGPUDirect RDMAのドキュメントを参照すると、以下のような記述がある。

We can distinguish between three situations, depending on what is on the path between the GPU and the third-party device:

  • PCIe switches only
  • single CPU/IOH
  • CPU/IOH <-> QPI/HT <-> CPU/IOH

The first situation, where there are only PCIe switches on the path, is optimal and yields the best performance. The second one, where a single CPU/IOH is involved, works, but yields worse performance ( especially peer-to-peer read bandwidth has been shown to be severely limited on some processor architectures ). Finally, the third situation, where the path traverses a QPI/HT link, may be extremely performance-limited or even not work reliably.

要するに、GPUとNVME-SSDを接続するパスの中で、マルチプロセッサシステムでQPIを経由するものはアウト(実際に試したことはあるが、強烈に遅い)。CPUがPCIeのRoot Complexとして振る舞うものも、動作はするがベストではなく、性能上の問題が生じる可能性がある。

実際、1枚あたり3.2GBのSeqRead性能を持つIntel DC P4600 (2.0TB; HHHL)を3枚束ねて(クエリ処理速度の影響を受けない)Raw-I/Oの性能を計測してみると、Broadwell-EP世代では7.1GB/s程度、Skylake-SP世代のプロセッサでは8.5GB/s程度で転送性能が頭打ちになってしまった。困ったものである。

PCIeバスの最適化を考える

ここまでのTry&Errorで明らかになったのは、NVME-SSDのように十分な転送速度を持つストレージとGPUを直結する場合、もはやストレージの側は律速要因ではなく、バスを制御するCPUの側がボトルネックとなり得るという点である。
したがって、ホストRAMに転送されたレコードを処理するというソフトウェア実行の負荷だけでなく、PCIeバス上を流れるデータ転送の負荷という観点においても、CPUの負荷を下げるという必要が生じてくる。

ここで目を付けたのがI/O拡張ボックス。
これは元々、窮屈なラックサーバに搭載可能な分よりも多数のデバイスを搭載するための機器で、ホストシステムへはコンパクトなLow ProfileのPCIeカードで接続すれば、その先に搭載したNVME-SSDGPUをあたかもローカル機器であるかのように使用する事ができる。
また製品によっては、I/O拡張ボックス側にPCIeスイッチを組込んでおり、同一ボックス内に搭載したデバイス同士であれば、P2P DMAは単純にボックス内に閉じたデータ転送となり、ホストシステムには全く影響を与えない。

その条件に該当するのがNEC ExpEtherで、この製品はI/O拡張ボックス側に4個のPCIeスロット(PCIe 3.0 x8)を備えており、PCIeスイッチを挟んで、ホストシステムへは40G Ehternetで接続する。このPCIeスイッチを活用する事で、ホストCPUに負荷を与えることなく、NVME-SSDからGPUへとP2P DMAによるデータ転送が行えるハズである。

PCIeバスの接続トポロジをブロック図で示すと以下のようになる。
データ転送負荷の最も大きくなるNVME-SSDGPU間の通信は、I/O拡張ボックスに内蔵のPCIeスイッチがこれを仲介するため、ホストシステムの負荷とはならない。I/O拡張ボックスからホストシステムへのデータ転送は、前処理が終わった後の小さなデータ断片のみとなる。

PostgreSQL上では、各I/O拡張ボックスに搭載されたNVME-SSDごとにパーティションを作成し、v11の新機能であるHash-Partitioningによりデータ分散を行う。このように構成する事で、各I/O拡張ボックスごとにデータ量が概ね平滑化され、各ボックスの処理時間が極端に違うという事がなくなる。


ベンチマーク

今回、NEC様のご協力により、ExpEther 40G (4slot) を3台お借りしてベンチマークを行う事ができた。
主なハードウェア環境は以下の通りで、3台のExpEtherにはそれぞれGPUを1枚とNVME-SSDを2枚ずつ搭載している。
データサイズは全体として1055GBで、各I/O拡張ボックスにはlineorderテーブルの一部が351GBずつ格納されている。

これまで同様にStar Schema Benchmarkで性能を計測した結果が以下の通り。
シングルノードのPostgreSQLにも関わらず、最大で13.5GB/sものクエリ処理速度を記録している。
面白い事に、I/O拡張ボックス上のSSDからホストシステムへデータを読み出した時のRaw-I/O性能(つまりSQL処理を挟まないタダのデータ転送速度)である8.8GB/sをも上回っている。

しかも注目すべきは、これはI/O拡張ボックス3台という最小構成に近い構成での結果であり、1台あたり約4.5GB/sというクエリ処理速度と、8.0TB*1というストレージ容量を増設可能である、という点である。
これは、台数を並べればDWH専用機にも比肩し得る処理性能を、GPUやNVME-SSDという最新ハードウェアの性能をフルに引き出すようソフトウェアを工夫する事で、シンプルなシングルノード構成のPostgreSQLで構築できてしまうという事を意味する。

まとめ&告知

ここ一年ほど取り組み続けた『GPUによるI/O性能の高速化』については、なんとかめでたくも、当初の目標性能であるシングルノード10GB/sを達成する事ができた。
この水準の処理能力・データベース容量の想定としては、中堅企業~大企業の部門/拠点規模でのログデータの集積・集計を行うようなワークロード。おそらくは従来であればRDBMSではなくHadoopベースのソリューションを検討していたであろう領域。総データサイズとしては、ボリュームゾーンとなるであろう~数十TBまでの範囲であれば、特に複雑な構成を作り込むまでもなく、シンプルなシングルノード構成のPostgreSQLで十分に捌く事も可能だろう。

今回の内容は、9/13(木)~9/14(金)に開催のGPU Technology Conference Japan 2018(於・品川高輪プリンスホテル)の『GTC JAPAN 2018 INCEPTION AWARD』セッションの中で発表する他、ポスターセッションでも発表場所で待機しているので、ぜひお越しいただきたい。
www.nvidia.com

また、より詳しい内容は、9/19(水)~9/21(金)に開催のDB Tech Showcase(於・秋葉原UDX)でも発表を行う。こちらは45分のノーマルセッションなので、よりじっくりと、詳しい内容に興味があるという方は、ぜひこちらへのご参加もご検討いただきたい。
www.db-tech-showcase.com

*1:Intel DC P4600 4.0TB版を使った場合