Advent Calendar最終日の今回は、少し大物としてPostgreSQLのMPPミドルウェア「Stado」の導入方法を紹介します。
Stado: The Open Source MPP Solution
https://launchpad.net/stado
■「MPP」とは何か
皆さんは「MPP」という言葉を聞いたことがあるでしょうか。
コンピュータの世界で「MPP」と言えば「Massive Parallel Processing」、日本語で言うところの「超並列処理」のことを指します。
Massively parallel (computing) - Wikipedia, the free encyclopedia
http://en.wikipedia.org/wiki/Massive_parallel_processing
データベースの世界で「MPP」と言うと、通常は「シェアードナッシング・アーキテクチャ」のスケーラブルな並列処理用のコンピュータアーキテクチャのことを指します。ベンダ製品で言うと、Teradata、Netezza、Greenplumなどが有名どころでしょう。
MPPは昔からデータウェアハウス(DWH)と呼ばれる領域で採用されてきたことからも分かる通り、特に大規模なデータの分析や集計処理に威力を発揮します。
(実は、筆者は新入社員の頃、PostgreSQLを使ったオープンソースのMPPの研究開発プロジェクトに参加していたこともあり、MPPテクノロジーにはちょっと思い入れがあったりします。ちなみに、学生の頃には今で言うHadoopのような分散処理の研究をしていました。)
■PostgreSQL用MPPミドルウェア「Stado」
そのMPPのアーキテクチャをPostgreSQLと組み合わせて実現するためのオープンソースのミドルウェアが「Stado」です。
Stado: The Open Source MPP Solution
https://launchpad.net/stado
Stadoは、複数のPostgreSQLサーバを束ねて、あたかも単一のデータベースサーバであるかのように見せることができるミドルウェアです。
Stadoは、前々回のエントリで紹介したパーティショニングのうち、「ハッシュパーティショニング」の機能を提供します。Stadoを使うことによって、大容量のデータに対して並列処理をすることができ、単体のPostgreSQLと比べて実行時間を大幅に短縮することができます。
Stadoの紹介をしているとこれもまた長くなりますので、Stadoの概要については上記の資料をご参照ください。
今回は、このStadoを実際に導入する手順を説明します。
とは言っても、誰もが複数台のサーバを用意できるわけでもないでしょうから、今回は1台のサーバにマルチコアCPUと複数のハードディスクを積んで、一台のサーバで並列処理をする環境を構築する方法を解説します。
以下のように、ディスクを4本積んでいるサーバで並列処理をさせることを想定してStadoの導入を行ってみます。
■導入手順
Stadoの大まかな導入手順は以下の通りです。
- Stadoのインストール
- PostgreSQLのセットアップ
- Stadoのセットアップ
- ユーザデータベースの作成
- テーブルスペースへのパーティションの移動
- テーブルの作成とデータのロード
■導入環境
今回Stadoを導入した環境は以下の通りです。
- NEC Express5800 GT110b
- Xeon Intel Xeon X3440 2.53GHz (1P4C)
- Unbeffered ECC 16GB
- Hitachi Deskstar 7K1000 HDS72101
- Red Hat Enterprise Linux 6.3 (x86_64)
今回、PostgreSQLは9.2を、JDKはOpenJDKの1.6.0を使っています。
[snaga@devsv03 ~]$ rpm -qa | grep postgresql postgresql92-9.2.2-1PGDG.rhel6.x86_64 postgresql92-devel-9.2.2-1PGDG.rhel6.x86_64 postgresql92-server-9.2.2-1PGDG.rhel6.x86_64 postgresql92-contrib-9.2.2-1PGDG.rhel6.x86_64 postgresql92-libs-9.2.2-1PGDG.rhel6.x86_64 [snaga@devsv03 ~]$ rpm -qa | grep openjdk java-1.6.0-openjdk-devel-1.6.0.0-1.45.1.11.1.el6.x86_64 java-1.6.0-openjdk-1.6.0.0-1.45.1.11.1.el6.x86_64 [snaga@devsv03 ~]$PostgreSQLとOpenJDKのインストールは完了しているものとして、ここからはStadoの導入を進めていきます。
■Stadoのインストール
まずは、Stadoのソースコードを取得します。
通常は、分散ソースコード管理システムであるBazaarを使って以下から取得します。
https://code.launchpad.net/~sgdg/stado/stado
[snaga@devvm03 tmp]$ bzr branch lp:~sgdg/stado/stado You have not informed bzr of your Launchpad ID, and you must do this to write to Launchpad or access private data. See "bzr help launchpad-login". Branched 55 revision(s). [snaga@devvm03 tmp]$とは言え、Bazzarをインストールしているユーザが多いとも思えないので、以下にソースコードとコンパイル済のjarファイルのパッケージを用意しました。
http://www.uptime.jp/go/stado
上記のURLから stado-20121223.tar.gz と install.sh スクリプトを取得します。
install.shスクリプトは、root権限で実行すると、OSアカウントのstadoユーザとstadoグループを作成し、必要なファイルを/usr/local/stadoにインストールします。
[snaga@devsv03 stado]$ wget http://www.uptime.jp/downloads/stado/stado-20121223.tar.gz (...snip...) [snaga@devsv03 stado]$ wget http://www.uptime.jp/downloads/stado/install_stado.sh (...snip...) [snaga@devsv03 stado]$ ls install_stado.sh stado-20121223.tar.gz [snaga@devsv03 stado]$ tar zxf stado-20121223.tar.gz [snaga@devsv03 stado]$ ls install_stado.sh stado-20121223/ stado-20121223.tar.gz [snaga@devsv03 stado]$ cd stado-20121223 [snaga@devsv03 stado-20121223]$ ls -F bin/ build.xml docs/ lib/ README.TXT stado.config build/ dist/ jars/ misc/ src/ [snaga@devsv03 stado-20121223]$ su Password: [root@devsv03 stado-20121223]# sh ../install_stado.sh [root@devsv03 stado-20121223]# ls -l /usr/local/stado/ total 16 drwxr-xr-x. 2 stado stado 4096 Dec 23 18:06 bin/ drwxr-xr-x. 2 stado stado 4096 Dec 23 18:06 config/ drwxr-xr-x. 2 stado stado 4096 Dec 23 18:06 lib/ drwxrwxr-x. 2 stado stado 4096 Dec 23 18:06 log/ [root@devsv03 stado-20121223]#
■PostgreSQLのセットアップ
Stadoのインストールが終わったら、まずはPostgreSQLの設定を行います。
・基本設定
postgresql.confの設定を変更した項目は以下の通りです。
listen_addresses = '*' max_connections = 100 shared_buffers = 2GB work_mem = 2GB maintenance_work_mem = 2GB wal_buffers = 32MB checkpoint_segments = 128 checkpoint_timeout = 60min log_filename = 'postgresql-%Y%m%d.log' log_min_duration_statement = 0 log_checkpoints = on log_connections = on log_disconnections = on log_line_prefix = '[%t] %p: ' log_temp_files = 0 autovacuum = offPostgreSQLの設定を行ったら、PostgreSQLサーバを起動します。
・テーブルスペースの作成
PostgreSQLサーバを起動したら、デフォルトのデータベースクラスタ /var/lib/pgsql/9.2/data 以外にテーブルスペースを作成します。
これらのテーブルスペースは、データベースクラスタとは別のディスク上に配置し、それによってI/O処理を分散させる目的で使用します。
ここでは、/disk/disk2, /disk/disk3, /disk/disk4 に、合計3本のディスクをマウントしているものとして、それらのディスクにそれぞれ tblspc2, tblspc3, tblspc4 というテーブルスペースを作成する設定を行います。
まず、テーブルスペースとして使用するディレクトリを作成し、postgresユーザ/postgresグループを所有者として権限を設定します。
[root@devsv03 pgsql]# df Filesystem 1K-blocks Used Available Use% Mounted on /dev/sda3 936146792 739057756 148768328 84% / /dev/sda1 101086 12010 83857 13% /boot tmpfs 8213720 0 8213720 0% /dev/shm /dev/sdb1 961432072 135545524 777048548 15% /disk/disk2 /dev/sdc1 961432072 53769008 858825064 6% /disk/disk3 /dev/sdd1 961432072 134776980 777817092 15% /disk/disk4 [root@devsv03 pgsql]# [root@devsv03 pgsql]# mkdir /disk/disk2/pgsql [root@devsv03 pgsql]# mkdir /disk/disk3/pgsql [root@devsv03 pgsql]# mkdir /disk/disk4/pgsql [root@devsv03 pgsql]# chown postgres:postgres /disk/disk4/pgsql /disk/disk3/pgsql /disk/disk2/pgsql次に、作成したディレクトリをテーブルスペースとしてPostgreSQL上で登録します。
postgres=# select * from pg_tablespace; spcname | spcowner | spcacl | spcoptions ------------+----------+--------+------------ pg_default | 10 | | pg_global | 10 | | (2 rows) postgres=# create tablespace tblspc2 location '/disk/disk2/pgsql'; CREATE TABLESPACE postgres=# create tablespace tblspc3 location '/disk/disk3/pgsql'; CREATE TABLESPACE postgres=# create tablespace tblspc4 location '/disk/disk4/pgsql'; CREATE TABLESPACE postgres=# select * from pg_tablespace; spcname | spcowner | spcacl | spcoptions ------------+----------+--------+------------ pg_default | 10 | | pg_global | 10 | | tblspc2 | 10 | | tblspc3 | 10 | | tblspc4 | 10 | | (5 rows) postgres=#データベースクラスタ内の pg_tblspc ディレクトリの中身を確認して、テーブルスペースが作成されたことを確認します。
[root@devsv03 pgsql]# ls -l /var/lib/pgsql/9.2/data/pg_tblspc total 0 lrwxrwxrwx. 1 postgres postgres 17 Dec 23 18:38 16384 -> /disk/disk2/pgsql lrwxrwxrwx. 1 postgres postgres 17 Dec 23 18:38 16385 -> /disk/disk3/pgsql lrwxrwxrwx. 1 postgres postgres 17 Dec 23 18:38 16386 -> /disk/disk4/pgsql [root@devsv03 pgsql]#これでテーブルスペースの作成は完了です。
・データベースユーザの作成
Stadoから接続するためのデータベースユーザを作成します。
このユーザは「Stado→PostgreSQL」の間で接続する際のデータベースユーザになります(ユーザからは直接は見えないユーザです)。ここでは「stado」という名前でデータベースユーザを作成します。
[stado@devsv03 ~]$ createuser -d -E -U postgres -P stado Enter password for new role: Enter it again: [stado@devsv03 ~]$ psql -h localhost -U stado postgres psql (9.2.2) Type "help" for help. postgres=> \q [stado@devsv03 ~]$ここまででPostgreSQLのセットアップは完了です。
■Stadoのセットアップ
・Stadoの設定ファイル
/usr/local/stado/config にある stado_agent.config は以下を変更します。
xdb.coordinator.host=127.0.0.1これは「エージェントノードから見たコーディネータノードのホスト名/IPアドレス」ですが、今回は一台のサーバの中でエージェントもコーディネータも動作させるため、上記のような設定となります。
同じディレクトリにある stado.config は、特に変更する項目はありません。ノードが4台であること、すべて 127.0.0.1 として扱うこと、として各種のパラメータが設定されていることを確認してください。
xdb.port=6453 xdb.maxconnections=10 xdb.default.dbusername=stado xdb.default.dbpassword=stado xdb.default.dbport=5432 xdb.default.threads.pool.initsize=2 xdb.default.threads.pool.maxsize=10 xdb.metadata.database=XDBSYS xdb.metadata.dbhost=127.0.0.1 xdb.nodecount=4 xdb.node.1.dbhost=127.0.0.1 xdb.node.2.dbhost=127.0.0.1 xdb.node.3.dbhost=127.0.0.1 xdb.node.4.dbhost=127.0.0.1 xdb.coordinator.node=1・メタデータベースとStado管理者ユーザの作成
ここまで設定ができたら、gs-createmdb.shコマンドを使ってStadoのメタデータベースを作成します。このメタデータベースでは、ノードの情報や、テーブルのパーティション情報などを管理するものです。
この時、同時にStadoの管理者ユーザの情報も(メタデータベース内に)作成されます。ここでは、Stadoの管理者ユーザを「stadoadm」として作成しています。
[stado@devsv03 ~]$ cd /usr/local/stado/bin [stado@devsv03 bin]$ ./gs-createmddb.sh -u stadoadm -p password Executed Statement: create table xsystablespaces ( tablespaceid serial, tablespacename varchar(255) not null, ownerid int not null, primary key(tablespaceid)) Executed Statement: create unique index idx_xsystablespaces_1 on xsystablespaces (tablespacename) (...snip...) Executed Statement: create unique index idx_xsyschecks_1 on xsyschecks (constid, seqno) Executed Statement: alter table xsyschecks add foreign key (constid) references xsysconstraints (constid) User stadoadm is created [stado@devsv03 bin]$いろいろなメッセージが出て、最後に「User [USER] is created」と出たらメタデータベースの作成は成功です。
■コーディネータプロセスの起動
メタデータベースの作成が終わったら、コーディネータプロセスを起動します。コーディネータプロセスの起動には gs-server.sh スクリプトを使います。
[stado@devsv03 bin]$ ./gs-server.sh Starting.... [stado@devsv03 bin]$ ps -aef | grep stado root 29892 29721 0 18:59 pts/3 00:00:00 su - stado stado 29893 29892 0 18:59 pts/3 00:00:00 -bash stado 30045 1 2 19:06 pts/3 00:00:00 java -classpath ../lib/stado.jar:../lib/log4j.jar:../lib/postgresql.jar: -Xms512M -Xmx512M -Xss256K -Dconfig.file.path=../config/stado.config org.postgresql.stado.util.XdbServer postgres 30064 29604 0 19:06 ? 00:00:00 postgres: stado XDBSYS 127.0.0.1(48401) idle stado 30099 29893 1 19:06 pts/3 00:00:00 ps -aef stado 30100 29893 0 19:06 pts/3 00:00:00 grep stado [stado@devsv03 bin]$Javaのプロセスが起動したら成功です。
■エージェントプロセスの起動
コーディネータの起動ができたら、次にエージェントプロセスの起動を行います。
エージェントプロセスは gs-agent.sh スクリプトで行い、-nオプションでStadoクラスタ内におけるエージェントの番号を指定します。
[stado@devsv03 bin]$ ./gs-agent.sh -n 4 Starting.... [stado@devsv03 bin]$ ps -aef | grep stado root 29892 29721 0 18:59 pts/3 00:00:00 su - stado stado 29893 29892 0 18:59 pts/3 00:00:00 -bash stado 30045 1 0 19:06 pts/3 00:00:00 java -classpath ../lib/stado.jar:../lib/log4j.jar:../lib/postgresql.jar: -Xms512M -Xmx512M -Xss256K -Dconfig.file.path=../config/stado.config org.postgresql.stado.util.XdbServer postgres 30064 29604 0 19:06 ? 00:00:00 postgres: stado XDBSYS 127.0.0.1(48401) idle stado 30112 1 4 19:07 pts/3 00:00:00 java -classpath ../lib/stado.jar:../lib/log4j.jar:../lib/postgresql.jar: -Xms256M -Xmx256M -Dconfig.file.path=../config/stado_agent.config org.postgresql.stado.util.XdbAgent -n 4 stado 30135 29893 1 19:07 pts/3 00:00:00 ps -aef stado 30136 29893 0 19:07 pts/3 00:00:00 grep stado [stado@devsv03 bin]$
■ユーザーデータベースの作成
エージェントプロセスが起動したら、ユーザデータベースを作成することができます。
gs-createdb.shコマンドを使って、ユーザデータベースを作成します(メタデータベースを作成するコマンド gs-createmdb.sh とは違うコマンドであることに注意してください。名前が似ていますが)
[stado@devsv03 bin]$ ./gs-createdb.sh -d testdb -u stadoadm -p password -n 1,2,3,4 OK [stado@devsv03 bin]$ユーザデータベースを作成したら、gs-cmdline.shコマンドでデータベースの状態を確認します。
[stado@devsv03 bin]$ ./gs-cmdline.sh -d testdb -u stadoadm -p password Stado -> show databases; +------------------------------+ | DATABASE | STATUS | NODES | +------------------------------+ | testdb | Started | 1,2,3,4 | +------------------------------+ 1 row(s). Stado -> [stado@devsv03 bin]$show databasesコマンドの結果を見ると、ここで作成したデータベースtestdbは、ステータスは利用開始されており、ノードは1から4に配置されていることが分かります。
■パーティションのテーブルスペースへの移動
データベースの一覧を見ると、今回作成したユーザデータベースtestdbが4つのパーティションを持っていることが分かります。gs-createdb.shコマンドを使ってStado上で作成した "testdb" というデータベースは、実際には "__testdb__N1" から "__testdb__N4" というパーティションに分割されています。
ここで、これらパーティションのテーブルスペースを見ると、すべて同じデフォルトのテーブルスペースに配置されていることが分かります。
postgres=> SELECT datname,dattablespace,spcname postgres-> FROM pg_database d LEFT OUTER JOIN pg_tablespace s postgres-> ON d.dattablespace=s.oid; datname | dattablespace | spcname --------------+---------------+------------ template1 | 1663 | pg_default template0 | 1663 | pg_default postgres | 1663 | pg_default XDBSYS | 1663 | pg_default __testdb__N1 | 1663 | pg_default __testdb__N2 | 1663 | pg_default __testdb__N3 | 1663 | pg_default __testdb__N4 | 1663 | pg_default (8 rows) postgres=>このままでは、すべてのパーティションが単一のディスク上に配置されてしまってクエリのI/O処理が分散されませんので、先ほど作成したテーブルスペースにこれらのデータベースパーティションを移動させます。
まずは、gs-dbstop.sh コマンドを使って一旦データベースを停止させます。(内部的にStadoのコーディネータプロセスからPostgreSQLインスタンスへの切断を終了します)
[stado@devsv03 bin]$ ./gs-dbstop.sh -u stadoadm -p password -d testdb Database(s) testdb stopped. [stado@devsv03 bin]$データベースを停止したら、各パーティションをそれぞれのテーブルスペースに移動させます。
[stado@devsv03 bin]$ psql -U postgres postgres psql (9.2.2) Type "help" for help. postgres=# ALTER DATABASE "__testdb__N2" SET TABLESPACE tblspc2; ALTER DATABASE postgres=# ALTER DATABASE "__testdb__N3" SET TABLESPACE tblspc3; ALTER DATABASE postgres=# ALTER DATABASE "__testdb__N4" SET TABLESPACE tblspc4; ALTER DATABASE postgres=# SELECT datname,dattablespace,spcname postgres-# FROM pg_database d LEFT OUTER JOIN pg_tablespace s postgres-# ON d.dattablespace=s.oid; datname | dattablespace | spcname --------------+---------------+------------ template1 | 1663 | pg_default template0 | 1663 | pg_default postgres | 1663 | pg_default XDBSYS | 1663 | pg_default __testdb__N1 | 1663 | pg_default __testdb__N2 | 16384 | tblspc2 __testdb__N3 | 16385 | tblspc3 __testdb__N4 | 16386 | tblspc4 (8 rows) postgres=# \q [stado@devsv03 bin]$ ./gs-dbstart.sh -u stadoadm -p password -d testdb Database(s) testdb started. [stado@devsv03 bin]$テーブルスペースへの移動が終わったら、最後にgs-dbstart.shコマンドを使ってデータベースを再開させます。
■ユーザデータベースへの接続
ここまで終われば、Stadoのセットアップは完了です。Stadoのコーディネータプロセスにpsqlコマンドを使って通常のPostgreSQLと同じように接続することができます。(ポート番号はstado.confgで指定したポート番号、ユーザはメタデータベース作成時に指定したユーザになります)
[stado@devsv03 bin]$ psql -p 6453 -h localhost -U stadoadm testdb Password for user stadoadm: psql (9.2.2, server 9.0.1) WARNING: psql version 9.2, server version 9.0. Some psql features might not work. Type "help" for help. testdb=>
■テーブルの作成とデータのロード
それでは、実際にユーザデータベース testdb の中にテーブルを作ってみます。
パーティションに分割させずにすべてのノードに持たせるテーブルはCREATE TABLE文に "REPLICATED" の修飾子を付加します。
CREATE TABLE orders ( o_orderkey INTEGER, o_custkey INTEGER, o_orderstatus CHAR(1), o_totalprice REAL, o_orderDATE DATE, o_orderpriority CHAR(15), o_clerk CHAR(15), o_shippriority INTEGER, o_comment VARCHAR(79) ) REPLICATED;パーティション分割させるテーブルは、CREATE TABLE文でパーティションキーを指定して "PARTITIONING KEY ... ON ALL" の修飾子を付加します。
CREATE TABLE orders2 ( o_orderkey INTEGER, o_custkey INTEGER, o_orderstatus CHAR(1), o_totalprice REAL, o_orderDATE DATE, o_orderpriority CHAR(15), o_clerk CHAR(15), o_shippriority INTEGER, o_comment VARCHAR(79) ) PARTITIONING KEY o_orderkey ON ALL;以下は、実際に CREATE TABLE 文を記述したスクリプトを実行してテーブルを作成している様子です。
testdb=> \i create_tables.sql CREATE TABLE CREATE TABLE CREATE TABLE CREATE TABLE testdb=> \d+ List of relations Schema | Name | Type | Owner | Size | Description --------+-----------+-------+-------+---------+------------- public | lineitem | table | stado | 0 bytes | public | lineitem2 | table | stado | 0 bytes | public | orders | table | stado | 0 bytes | public | orders2 | table | stado | 0 bytes | (4 rows) testdb=>テーブルを作成した後、gs-cmdline.shコマンドを起動して show tables コマンドを実行すると、作成したテーブルがどのように配置されているかを確認することができます。
以下の例では、ordersテーブルとlineitemテーブルはレプリケーションテーブルとして全4ノードに同じものを配置、orders2テーブルとlineitem2テーブルはパーティションテーブルとして、それぞれo_orderkeyカラムとl_orderkeyカラムをパーティションキーとしてハッシュ分割して4分割されていることが分かります。
[stado@devsv03 ~]$ cd /usr/local/stado/bin/ [stado@devsv03 bin]$ ./gs-cmdline.sh -u stadoadm -p password -d testdb Stado -> show tables; +-----------------------------------------------------+ | TABLE | TABLE_PARTITIONING_COLUMN | TABLE_NODES | +-----------------------------------------------------+ | lineitem | | 1,2,3,4 | | lineitem2 | l_orderkey | 1,2,3,4 | | orders | | 1,2,3,4 | | orders2 | o_orderkey | 1,2,3,4 | +-----------------------------------------------------+ 4 row(s). Stado ->データのローディングにはCOPYコマンドを使うことができます。
以下は、COPYコマンドを含むスクリプトを実行してデータをロードしている様子です。データロード実行後にテーブルサイズが大きくなっていることが分かります。
testdb=> \i load_tables.sql Timing is on. Time: 162623.103 ms Time: 64810.198 ms Time: 763729.597 ms Time: 320365.227 ms testdb=> \d+ List of relations Schema | Name | Type | Owner | Size | Description --------+-----------+-------+-------+---------+------------- public | lineitem | table | stado | 8326 MB | public | lineitem2 | table | stado | 2081 MB | public | orders | table | stado | 1979 MB | public | orders2 | table | stado | 495 MB | (4 rows) testdb=>
■クエリの実行
データをロードしたテーブルには、psqlコマンドを使って通常のPostgreSQLと同じようにクエリを実行することができます。
testdb=> select count(*) from orders; count(*) ---------- 15000000 (1 row) Time: 1870.665 ms testdb=> select count(*) from orders2; count(*) ---------- 15000000 (1 row) Time: 650.026 ms testdb=>
■まとめ
今回は、PostgreSQLを使ってMPPを実現するミドルウェア「Stado」について、その導入方法をご紹介してきました。(かなり駆け足になってしまいましたが)
BigDataやデータ分析の重要性が語られる時代になってきました。巷ではNoSQLなどの「新しいテクノロジー」が耳目を集めていますが、エンジニアの持っているスキルや業務データとの親和性を考えると、RDBMSが活躍できる余地はまだまだあるように(個人的には)感じています。
興味を持たれましたら、ぜひ試してみていただければと思います。
では、Happy Holidays!
■参考資料
Stado - The Open Source MPP Solution | StormDB
http://www.stormdb.com/community/stado
Stadoマニュアル 日本語(一部)対訳版
http://www.uptime.jp/go/stado/
PostgreSQL並列分散ミドルウェア「Stado」の紹介と検証報告
http://www.uptime.jp/ja/resources/techdocs/2012/07/stado/
0 件のコメント:
コメントを投稿