PG-Stromを使って見る
PG-Strom っていうRDBMSがあります。もう少し正確に言うと、PostgreSQLのエクステンション(拡張モジュール)として動作するものです。
多くのRDBMSは、CPUを使って処理を行いますが、PG-Strom は GPUを活用した処理を提供してくれるので、ハマる処理だと非常に高速になります。
今回、手元にある余っていたマシンに PG-Strom v5 動作環境を構築したので、その手順を紹介します。
PG-Strom公式サイト(HeteroDB社):https://www.heterodb.com/
PG-Stromインストールガイド: https://heterodb.github.io/pg-strom/ja/install/#cuda-toolkit
今回の環境
やや古めの、手元に余っていたマシン1台を使用しました。こんな環境でも、GPUを使った際の速度差が出るのだから、面白いものです(詳細後述)。
- CPU: Core i3-7100T
- Mother board: H270
- Memory: 8GB
- SSD: SATA 120GB
- GPU: GeForce GTX-1070
OSインストール
今回は、PG-Stromの推奨環境である Red Hat Enterprise Linux 8 (RHEL 8) を使用しました。
RHEL 8 のインストールについては(これだけで少々長くなるので)別のエントリにて紹介しました。
sakaik.hateblo.jp
このエントリでは、RHEL 8 を、Minimal install した状態をスタート地点とします。
インストール手順概要
PG-Stromを動作させるために、概ね、以下の手順でインストール/設定を行います.
- 基本ツール群のインストール
- デフォルトのGPUドライバの無効化
- 使用するdnfリポジトリの有効化
- GPUドライバのインストール
- PostgreSQLとPostGISのインストールと設定
- PG-Stromのビルドと設定
- 動作確認
インストール手順(詳細)
基本ツール群のインストール
使用するツール群を、リポジトリからインストールする。
# dnf groupinstall 'Development Tools' -y # dnf install wget grubby -y
.
デフォルトのGPUドライバの無効化
OSS版NVIDIA GPUドライバnouveauを無効化しておく(念のため、事前に無効化しておくほうが安全、とのことなので)
# grubby --update-kernel=ALL --args='nouveau.modeset=0 rd.driver.blacklist=nouveau video=vesa:off' # reboot
.
使用するdnfリポジトリの有効化
EPELリポジトリを有効化
# subscription-manager repos --enable codeready-builder-for-rhel-8-$(arch)-rpms # dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm -y
HeteroDB Software Distribution Center リポジトリを有効化。
(ただし今回は PG-Strom v5をソースコードからビルドするので本リポジトリは使わない)
# dnf install https://heterodb.github.io/swdc/yum/rhel8-noarch/heterodb-swdc-1.2-1.el8.noarch.rpm -y
.
GPU(CUDA)ドライバのインストール
使用するOSやGPUに応じてインストール方法が異なります。NVIDIAのサイトにアクセスして、適切なインストール方法の情報を得ることにします。
https://developer.nvidia.com/accelerated-computing-toolkit
上記サイトにアクセスし、今回は、
を指定しました。最後の Install Type で rpm(local)では rpm(network)でも良かったのですが、手元にrpmを置いて作業をしたかったので、今回はこちらを選択しました。
入力を終えると、画面下部に、CUDAドライバのインストール用コマンドがサジェストされるので、一旦手元にコピーして、順次実行するます。
サジェスト内容:
>Base Installer Installation Instructions: wget https://developer.download.nvidia.com/compute/cuda/12.2.1/local_installers/cuda-repo-rhel8-12-2-local-12.2.1_535.86.10-1.x86_64.rpm sudo rpm -i cuda-repo-rhel8-12-2-local-12.2.1_535.86.10-1.x86_64.rpm sudo dnf clean all sudo dnf -y module install nvidia-driver:latest-dkms sudo dnf -y install cuda
実際の実行コマンド(rootで作業しているのでsudo部分少々変更):
# wget https://developer.download.nvidia.com/compute/cuda/12.2.1/local_installers/cuda-repo-rhel8-12-2-local-12.2.1_535.86.10-1.x86_64.rpm # rpm -i cuda-repo-rhel8-12-2-local-12.2.1_535.86.10-1.x86_64.rpm # dnf clean all # dnf -y module install nvidia-driver:latest-dkms # dnf -y install cuda
rpmファイルがかなり大きい(4.6GB)ので、この部分にかなり時間がかかりました。
インストール完了後には、 nvidia-smi コマンドで動作環境を確認することができます。
# nvidia-smi Wed Aug 23 14:14:15 2023 +---------------------------------------------------------------------------------------+ | NVIDIA-SMI 535.86.10 Driver Version: 535.86.10 CUDA Version: 12.2 | |-----------------------------------------+----------------------+----------------------+ | GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |=========================================+======================+======================| | 0 NVIDIA GeForce GTX 1070 Off | 00000000:02:00.0 Off | N/A | | 0% 43C P0 32W / 151W | 0MiB / 8192MiB | 0% Default | | | | N/A | +-----------------------------------------+----------------------+----------------------+ +---------------------------------------------------------------------------------------+ | Processes: | | GPU GI CI PID Type Process name GPU Memory | | ID ID Usage | |=======================================================================================| | No running processes found | +---------------------------------------------------------------------------------------+
PostgreSQLとPostGISのインストールと設定
PostgreSQLインストールのためのリポジトリを追加します。
# dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-8-x86_64/pgdg-redhat-repo-latest.noarch.rpm
PostgreSQLとPostGISをインストールします。今回は、PostgreSQL 15を使用(PG-Strom v5 の推奨環境)しているため、PostGIS にも 33_15 と明示してインストールします。
# dnf module disable postgresql -y # dnf install postgresql15-devel postgresql15-server -y # dnf install -y postgis33_15
PostgreSQLデータベースを初期化します。
# /usr/pgsql-15/bin/postgresql-15-setup initdb
PostgreSQLサーバを再起動します。
# systemctl start postgresql-15
.
念のためここで、PostgreSQLサーバに接続できることを確認しておきましょう。今回は手元で動作することをさっくりと確認したい用途なので、デフォルトユーザのまま作業を進めてしまいますが、必要に応じて適切にユーザを作成したり権限したりしてください。
# su postgres - bash-4.4$ psql postgres=# \l List of databases Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access privileges -----------+----------+----------+-------------+-------------+------------+-----------------+----------------------- postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc | template0 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc | =c/postgres + | | | | | | | postgres=CTc/postgres template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc | =c/postgres + | | | | | | | postgres=CTc/postgres (3 rows)
PG-Stromのビルドと設定
ここまで準備ができてようやく、本丸の PG-Strom の作業になります。あとちょっとです!
PG-Stromは、現在のリリースバージョンとしては v3 が最新ですが、まもなく(きっと1~2週間のうちには)大幅に改良された v5 がリリースされる見通しです。
というわけで、今回はGitHubで公開されている PG-Strom v5 のソースコードを取得して、ビルドして使用することにします。
PG-Stromのリポジトリは、https://github.com/heterodb/pg-strom なので、これをcloneしてビルドします。
作業フォルダの作成も含め、以下の手順になります。実はこの手順だと「pg-strom」フォルダが2段に作成されてしまって格好悪いのですが、今回はこれでやっちゃいました。お試しになる方は、よしなに。
$ mkdir pg-strom $ cd pg-strom $ git clone https://github.com/heterodb/pg-strom
make時には、インストール済PostgreSQLの設定ファイルの場所を指定する必要があります(設定を読み込んで適切にビルドしてくれるのです)。実行前に、"pg_config" がある場所を予め確認しておくと良いでしょう。
$ cd pg-strom/src/ $ make PG_CONFIG=/usr/pgsql-15/bin/pg_config
無事 make できたら、make install します。システムのフォルダへのコピーのためにroot権限が必要なため、sudoしています。
$ sudo make install PG_CONFIG=/usr/pgsql-15/bin/pg_config
PG-StromをPostgreSQLで使用するためには、postgresql.confにプリロードのライブラリを指定する必要があります。その他、公式マニュアルに従って、スレッドやメモリに関するいくつかの設定を変更しました。
# vi /var/lib/pgsql/15/data/postgresql.conf
shared_preload_libraries = '$libdir/pg_strom' # PG-Strom shared_buffers = 128MB # min 128kB (とりあえずデフォルトまま変更しなかった) max_worker_processes = 100 # for PG-Strom work_mem = 1GB # for PG-Strom
設定完了したら、PostgreSQLを再起動します。
$ sudo systemctl restart postgresql-15
以上で、PG-Stromが動作する環境の構築ができました!
動作確認
- 動作確認の準備
動作確認をしてみましょう。既出の方法で PostgreSQLに接続します。
確認用のデータベースを新規に作成して試してみることにします。今回は "pgstest"という名前にしました。
データベースの作成と接続
postgres=# CREATE DATABASE pgstest; postgres=# \c pgstest;
PostGISエクステンションと、PG-Stromエクステンションの有効化
pgstest=# CREATE EXTENSION postgis; pgstest=# CREATE EXTENSION pg_strom;
ちなみに、手順中の「postgresql.confへのプリロード指定記述の追加」を忘れていると、pg_stromエクステンションをCREATEするタイミングで以下のエラーが出ます。これが出たら「あ。手順すっとばした!」と恥じ入ると良いでしょう(何度も恥じ入りました....)。
pgstest=# CREATE EXTENSION pg_strom; ERROR: PG-Strom must be loaded via shared_preload_libraries
.
- PG-Stromによるクエリ処理の確認
まず、検証用のデータを作成します。以下のクエリは、緯度と経度を模した2つの数値1000万件をランダムに生成したテーブルを作ります。
CREATE TABLE points1000man (gid int primary key, x float8, y float8, category int); INSERT INTO points1000man ( SELECT x, pgstrom.random_float(0, 128.0, 146.5), pgstrom.random_float(0, 28.0, 45.6), pgstrom.random_int(0, 1,20 ) FROM generate_series(1,10000000) x);
例として以下のようなクエリを考えます。指定した点から一定距離にあるレコードを検索して返すクエリです。
SELECT ST_Distance(ST_MakePoint(137.0, 44.0), ST_MakePoint(x,y)) FROM points1000man WHERE ST_Distance(ST_MakePoint(137.0, 44.0), ST_MakePoint(x,y))<0.5;
実行に先立って、実行計画を確認してみます。GPUの使用が計画されていることが分かりますね。
pgstest=# explain SELECT ST_Distance(ST_MakePoint(137.0, 44.0), ST_MakePoint(x,y)) FROM points1000man pgstest-# WHERE ST_Distance(ST_MakePoint(137.0, 44.0), ST_MakePoint(x,y))<0.5; QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Gather (cost=1100.00..43864599.31 rows=3848070 width=8) Workers Planned: 2 -> Parallel Custom Scan (GpuScan) on points1000man (cost=100.00..43478792.31 rows=1603362 width=8) GPU Projection: st_distance('010100000000000000002061400000000000004640'::geometry, st_makepoint(x, y)) GPU Scan Quals: ((st_distance('010100000000000000002061400000000000004640'::geometry, st_makepoint(x, y))) < '0.5'::double precision) [rows: 11544210 -> 1603362] (5 rows)
実行結果(結果データは省略)。760msで結果を得ることができました。
pgstest=# SELECT ST_Distance(ST_MakePoint(137.0, 44.0), ST_MakePoint(x,y)) FROM points1000man WHERE ST_Distance(ST_MakePoint(137.0, 44.0), ST_MakePoint(x,y))<0.5; : (24142 rows) Time: 760.950 ms
PG-Stromは、pg_strom.enabledの値によってオンにしたりオフにしたりすることができます。オフにして確認してみます。
pgstest=# SET pg_strom.enabled=false;
オフにすると(つまり元のPostgreSQLの状態だと)、3.6secほどかかることがわかります。
pgstest=# SELECT ST_Distance(ST_MakePoint(137.0, 44.0), ST_MakePoint(x,y)) FROM points1000man WHERE ST_Distance(ST_MakePoint(137.0, 44.0), ST_MakePoint(x,y))<0.5; : (24142 rows) Time: 3623.610 ms (00:03.624)
このときの実行計画。PG-StromをオフにするとGPUは使用されないことが確認できます。
pgstest=# explain SELECT ST_Distance(ST_MakePoint(137.0, 44.0), ST_MakePoint(x,y)) FROM points1000man WHERE ST_Distance(ST_MakePoint(137.0, 44.0), ST_MakePoint(x,y))<0.5; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- Gather (cost=1000.00..140044399.75 rows=3333360 width=8) Workers Planned: 2 -> Parallel Seq Scan on points1000man (cost=0.00..139710063.75 rows=1388900 width=8) Filter: (st_distance('010100000000000000002061400000000000004640'::geometry, st_makepoint(x, y)) < '0.5'::double precision) (4 rows)
まとめ
という感じで、古い GTX1070でPG-Stromが動作することを確認できました。興味を持った方はぜひお試しください。
最近はこのように、仕事でPG-Stromの検証をしていることも多いので、性能比較などについては今後もブログを書いて行ければと思っています。
PG-Stromを仕事で活用してみたい、もしかしたら良いかも?などと思った方は連絡いただければ、お力になれる事があるかもしれません。ぜひぜひ。