この記事は PostgreSQL Advent Calendar 2023 の 12月 4日の記事です。
OrioleDBとは
OrioleDB は PostgreSQL開発者でもある Alexander Korotkov 氏が開発する新たなデータベースソフトウェアです。PostgreSQL をベースとしつつ PostgreSQL の基本アーキテクチャに起因する様々な制限や問題点を解消することを目的として「Row-level WAL」「Lock-less buffer access」「Undo log」といった大型の実装置き換えが含まれています。
その一方で OrioleDB はあくまでも PostgreSQL のテーブルアクセスメソッド等を提供する拡張モジュールという形で提供されています。現状は PostgreSQL本体への修正パッチもあるのですが、それは必要な機能を拡張モジュールとして導入できるようにするための修正であって、機能提供は拡張モジュール側に記述されています。
私は先日(2023年11月24日)開催された、日本PostgreSQLユーザ会主催の PostgreSQLカンファレンス2023 に運営者として携わりまして、そこで、Alexander Korotkov 氏にこの OrioleDB について講演してもらいました。本記事では、おそらく日本であまり知られていなかったであろう OrioleDB を紹介したことの補足として、実際に触ってみる手順などを紹介します。
OrioleDB のアーキテクチャについては、配布物内のドキュメントや、カンファレンス講演資料や氏の以前の講演資料 参照してください。
インストール手順
OrioleDB のインストールは、PostgreSQL をソースコードからビルド・インストールしたり、拡張モジュールをビルド・インストールしたことがある人なら、それほど難しいところがありません。
ビルド環境で必要なものは、PostgreSQLビルドと概ね同じです。以下は真っ新な Rocky Linux 9.1 で実行したコマンドです。
# dnf install -y git gcc bison flex python perl
# dnf install -y zlib-devel readline-devel libicu-devel openssl-devel libzstd-devel lz4-devel
# dnf install -y pip # 後で testgres を導入するため
比較用と postgresユーザを作るために通常の PostgreSQL16パッケージも導入しておきます。
# dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm
# dnf -qy module disable postgresql
# dnf install -y postgresql16-server
まず、OrioleDB用のパッチの当たった PostgreSQL を導入します。
gitリポジトリとして提供されていますが PostgreSQL全体を含んでいてサイズが大きいので最新版のスナップショットを取得すれば良いでしょう。orioledb の README.md に PostgreSQLメジャーバージョン系列ごとにリンクが用意されています。以下では PostgreSQL 16.x に対してパッチバージョン18 を当てたものを導入します。
# mkdir /usr/local/pgsql
# chown postgres:postgres /usr/local/pgsql
# su - postgres
$ wget https://github.com/orioledb/postgres/archive/refs/tags/patches16_18.zip
$ unzip patches16_18.zip
$ cd postgres-patches16_18/
$ ./configure --prefix=/usr/local/pgsql/16orioledb --enable-debug --with-openssl --with-zstd --with-lz4
$ make world-bin
$ make install-world-bin
$ cd -
インストールしたパッチ付き PostgreSQLにパスを通しておきます。また、PGDATA環境変数もセットしておきます。
$ cat > 16orioledb.env <<EOF
export PATH=/usr/local/pgsql/16orioledb/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/pgsql/16orioledb/lib:$LD_LIBRARY_PATH
export PGDATA=/var/lib/pgsql/16/odata
EOF
$ . 16orioledb.env
$ echo ". 16orioledb.env" >> .bash_profile
続いて、orioledb 拡張を導入します。リポジトリ最新版を使います(記事執筆時 2023年 12月 2日)。
一般的な拡張のインストール手順通りです。注意点は Makefile変数 ORIOLEDB_PATCHSET_VERSION を明示的に指定しておくことです。README.md の Installation の記述では記載は無いのですが、指定せずだと自動でうまく判断してくれない場合があるようです。
$ git clone https://github.com/orioledb/orioledb.git
$ cd orioledb
$ make USE_PGXS=1 ORIOLEDB_PATCHSET_VERSION=18
$ make USE_PGXS=1 ORIOLEDB_PATCHSET_VERSION=18 install
orioledb 拡張がインストールできたなら、initdb をして、設定を行います。
$ initdb --no-locale -E UTF8
$ vi $PGDATA/postgresql.conf
(以下を設定)
shared_preload_libraries = 'orioledb'
logging_collector = on
$ pg_ctl start
orioledb 拡張を組み込んだ PostgreSQL (即ち OrioleDB)が起動したなら、リグレッションテストも実行しておきましょう。リポジトリ最新版を使うときには大事な手順です。orioledb のリグレッションテストには testgresツールが使われているため、これを pip からローカルインストールしておきます。
$ pip install testgres
$ make USE_PGXS=1 ORIOLEDB_PATCHSET_VERSION=18 installcheck
このテストはそれなりに規模が大きくて、終わるまで数分待つことになります。本環境では「All checks are successful!」で無事テストを終えることができました。
動かしてみる
まずは、orioledb をデフォルトのテーブルアクセスメソッドとするデータベース db1 を作ります。
$ psql
postgres=# CREATE DATABASE db1;
postgres=# ALTER DATABASE db1 SET default_table_access_method TO orioledb;
postgres=# \q
orioledb用の postgresql.conf設定パラメータもいろいろあるのですが、まずは何もチューニングせずに pgbench を実行してみましょう。実行したマシンは、Azure の Standard D2s v3 (2 vcpu 数、8 GiB メモリ) です。
データ読み書きしてみることと、ノーマルな PostgreSQL と単純比較する狙いです。
$ pgbench -i -s 10 db1
$ pgbench -c 16 -T 120 -s 10 db1
pgbench (16rc1)
pgbench: warning: scale option ignored, using count from pgbench_branches table (10)
starting vacuum...end.
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 10
query mode: simple
number of clients: 16
number of threads: 1
maximum number of tries: 1
duration: 120 s
number of transactions actually processed: 159175
number of failed transactions: 0 (0.000%)
latency average = 12.062 ms
initial connection time = 45.113 ms
tps = 1326.491695 (without initial connection time)
3回実行して、tps = 1326.491695、1264.996140、1387.240085 。
ノーマル PostgreSQL 16 で同サーバで実行すると、tps = 1305.715921、1278.107693、1282.910015 です。
これだけの比較でノーマル PostgreSQL よりちょっと速いと言っても、あまり意味はありません。重要なことは、何にも考えず何もチューニングしなくとも同じように動作して同じ程度には性能が出るという点です。
拡張された PostgreSQL互換データベースソフトウェアが、通常の PostgreSQLよりも圧倒的に性能が上回る動作が可能であるとしも、そうするためのおぜん立てが容易ではないとなりますと使い勝手の悪い代物ととなります。通常の PostgreSQLと同じだと思って使って「ひどいことにはならない」というのは重要な利点です。
レプリケーションしてみる
続いてストリーミングレプリケーションを構築しています。
こちらも何も考えず、通常の PostgreSQL であるかのようにコマンドを実行してみましょう。
あらかじめ、1号機の postgresql.conf で listen_addresses = '*' を設定して、pg_hba.conf で 2号機からの レプリケーション接続を trust で許すように設定しておきます。
[postgres@orioledb1 ~]$ vi $PGDATA/postgresql.conf
(以下を設定)
listen_addresses = '*'
[postgres@orioledb1 ~]$ vi $PGDATA/pg_hba.conf
(以下を設定)
host replication all 10.0.0.5/32 trust
[postgres@orioledb2 ~]$ pg_basebackup -D $PGDATA -h 10.0.0.4 -R
[postgres@orioledb2 ~]$ pg_ctl start
waiting for server to start....2023-12-03 13:58:38.378 UTC [6301] LOG: registered custom resource manager "OrioleDB resource manager" with ID 129
2023-12-03 13:58:38.449 UTC [6301] LOG: OrioleDB public beta 3 started
2023-12-03 13:58:38.497 UTC [6301] LOG: redirecting log output to logging collector process
2023-12-03 13:58:38.497 UTC [6301] HINT: Future log output will appear in directory "log".
done
server started
ホットスタンバイ設定を自動生成する -R オプションを付けて、1号機(10.0.0.4) を -h オプションに指定して、pg_basebackup を実行します。
完了後に pg_ctl start で起動。手順は本当に通常の PostgreSQL と同じです。
しかしながら、ps コマンドでプロセスを調べると、orioledb 特有の仕組みが動作していることがわかります。「orioledb recovery worker」が並列で6つ動作しています。
[postgres@orioledb2 ~]$ ps x
PID TTY STAT TIME COMMAND
4770 pts/1 S 0:00 -bash
6301 ? Ss 0:00 /usr/local/pgsql/16orioledb/bin/postgres
6302 ? Ss 0:00 postgres: logger
6303 ? Ss 0:00 postgres: checkpointer
6304 ? Ss 0:00 postgres: background writer
6305 ? Ss 0:00 postgres: startup recovering 0000000100000000000000
6306 ? Ss 0:00 postgres: orioledb background writer
6307 ? Ss 0:00 postgres: orioledb recovery worker 3
6308 ? Ss 0:00 postgres: orioledb recovery worker 2
6309 ? Ss 0:00 postgres: orioledb recovery worker 1
6310 ? Ss 0:00 postgres: orioledb recovery worker 0
6311 ? Ss 0:00 postgres: orioledb recovery worker 5
6312 ? Ss 0:00 postgres: orioledb recovery worker 4
6313 ? Ss 0:00 postgres: walreceiver streaming 0/16000060
6314 pts/1 R+ 0:00 ps x
orioledb をデフォルトテーブルアクセスメソッドとしている db1 についてレプリケーション動作できいますし、
[postgres@orioledb1 ~]$ psql db1
db1=# UPDATE pgbench_accounts SET filler = 'test' WHERE aid = 12345;
UPDATE 1
[postgres@orioledb2 ~]$ psql db1
db1=# SELECT * FROM pgbench_accounts WHERE aid = 12345;
aid | bid | abalance | filler
-------+-----+----------+-------------------------------------------------------
-------------------------------
12345 | 1 | 0 | test
(1 row)
orioledb 拡張を使っていないデータベースについてもレプリケーションができています。
[postgres@orioledb1 ~]$ createdb db2
[postgres@orioledb1 ~]$ psql db2
db2=# CREATE TABLE t2 (id int primary key, v text);
CREATE TABLE
db2=# INSERT INTO t2 VALUES (1, 'foo');
INSERT 0 1
[postgres@orioledb2 ~]$ psql db2
db2=# SELECT * FROM t2;
id | v
----+-----
1 | foo
(1 row)
通常の PostgreSQL のレプリケーションと拡張された動作とがシームレスに機能しています。
ディレクトリを覗いてみる
OrioleDB は PostgreSQL標準のものとは全く異なるストレージエンジンですので、データベースクラスタディレクトリの内容も違っているはずです。
どうなっているでしょうか。
psql で orioledb をデフォルトテーブルアクセスメソッドにした db1 を参照すると、4つのシステムビューが自動的に作られています。テーブル圧縮の状態など、テーブル・インデックスについて orioledb固有の情報が表示されます。
[postgres@orioledb1 ~]$ psql db1
psql (16rc1)
Type "help" for help.
db1=# \d
List of relations
Schema | Name | Type | Owner
--------+----------------------+-------+----------
public | orioledb_index | view | postgres
public | orioledb_index_descr | view | postgres
public | orioledb_table | view | postgres
public | orioledb_table_descr | view | postgres
public | pgbench_accounts | table | postgres
public | pgbench_branches | table | postgres
public | pgbench_history | table | postgres
public | pgbench_tellers | table | postgres
(8 rows)
また、orioleテーブルアクセスメソッドを使ったテーブルの実行プランを調べてみますと、Custom Scan による実行プランになっていることがわかります。
b1=# EXPLAIN SELECT * FROM pgbench_accounts WHERE aid = 1234;
QUERY PLAN
-----------------------------------------------------------------------------
Custom Scan (o_scan) on pgbench_accounts (cost=0.17..8.19 rows=1 width=97)
Forward index scan of: pgbench_accounts_pkey
Conds: (aid = 1234)
(3 rows)
データベースクラスタディレクトリはどうなっているでしょうか。
orioledb_data、orioledb_undo ディレクトリが加わっています。
$ cd $PGDATA/
$ ls
PG_VERSION pg_commit_ts pg_replslot pg_twophase
base pg_dynshmem pg_serial pg_wal
current_logfiles pg_hba.conf pg_snapshots pg_xact
global pg_ident.conf pg_stat postgresql.auto.conf
log pg_logical pg_stat_tmp postgresql.conf
orioledb_data pg_multixact pg_subtrans postmaster.opts
orioledb_undo pg_notify pg_tblspc postmaster.pid
$ ls orioledb_data/
0000000000.xidmap 1 16388 6.xid control
$ ls orioledb_data/16388/
16462 16477-5.tmp 16482-7.map 16488-6.map 16489-7.tmp 16498
16476 16477-6.map 16483 16488-7.evt 16495 16498-5.map
16476-3.map 16477-6.tmp 16483-5.tmp 16488-7.map 16496 16498-6.map
16476-6.map 16482 16483-6.map 16489 16496-5.map
16476-7.evt 16482-3.map 16483-6.tmp 16489-6.map 16496-6.map
16476-7.map 16482-6.map 16488 16489-6.tmp 16496-7.evt
16477 16482-7.evt 16488-3.map 16489-7.map 16496-7.map
$ ls orioledb_undo/
0000000002 0000000003 0000000004
orioledb_data がデータのディレクトリです。
データベースごとのサブディレクトリ内にテーブルの格納データファイルがあります。
orioledb_undo は UNDOログのディレクトリです。更新ワークロードをかけるとこのファイルが増えていきローテーションします。
ここまでのまとめ
本記事としては以上とさせていただきます。
いかがでしたでしょうか。
通常の PostgreSQL と同じ使い勝手でありながら、異なるアーキテクチャで置き換えが施されたが新たなデータベースソフトウェア使える、という OrioleDB のすばらしさが伝わりましたでしょうか。
OrioleDB の各固有機能や性能向上の実力、また、それらを効果的に使う方法、といったことにつきましては、別の機会に記事にさせていただけましたらと思います。