PG-Strom インストール手順

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を使った際の速度差が出るのだから、面白いものです(詳細後述)。

OSインストール

 今回は、PG-Stromの推奨環境である Red Hat Enterprise Linux 8 (RHEL 8) を使用しました。
RHEL 8 のインストールについては(これだけで少々長くなるので)別のエントリにて紹介しました。
sakaik.hateblo.jp

このエントリでは、RHEL 8 を、Minimal install した状態をスタート地点とします。

インストール手順概要

 PG-Stromを動作させるために、概ね、以下の手順でインストール/設定を行います.

  • 基本ツール群のインストール
  • デフォルトのGPUドライバの無効化
  • 使用するdnfリポジトリの有効化
  • GPUドライバのインストール
  • PostgreSQLPostGISのインストールと設定
  • PG-Stromのビルドと設定
  • 動作確認

インストール手順(詳細)

基本ツール群のインストール

使用するツール群を、リポジトリからインストールする。

# dnf groupinstall 'Development Tools' -y
# dnf install wget grubby -y


.

デフォルトのGPUドライバの無効化

OSSNVIDIA 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                                                           |
+---------------------------------------------------------------------------------------+
PostgreSQLPostGISのインストールと設定

PostgreSQLインストールのためのリポジトリを追加します。

# dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-8-x86_64/pgdg-redhat-repo-latest.noarch.rpm

PostgreSQLPostGISをインストールします。今回は、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を仕事で活用してみたい、もしかしたら良いかも?などと思った方は連絡いただければ、お力になれる事があるかもしれません。ぜひぜひ。