pgbenchによるSlony-I 1.2.1の運用性に関する評価手順

SRA OSS, Inc. 日本支社

今回の運用性評価では、評価用ツールとしてPostgreSQL用のベンチマークツールであるpgbenchを、レプリケーションの確認には今回開発したコンペアツールを使用した。

コマンドを実行するマシンを区別するため、コマンドプロンプトの記述を表1のように定める。 「$」で表されるプロンプトは一般ユーザ、「#」は root ユーザとする。 シェルはbashを使用し、PostgreSQLをインストールした/usr/local/pgsql/binディレクトリにパスが通っているものとする。また、今回開発したコンペアツールはクライアントのホームディレクトリに置き、そこで実行することとする。

表1: コマンドプロンプトの区別
ノード ホスト名 コマンドプロンプト
クライアント client [client]$
PostgreSQLマスタサーバ db1 [db1]$
PostgreSQLスレーブサーバ db2 [db2]$
PostgreSQLスレーブサーバ db3 [db3]$

1.導入手順

Slony-I 1.2.1の導入手順を下記に示す。

コンパイル・インストール

Slony-I 1.2.1をソースコードからコンパイルしてインストールする。

Slony-I 1.2.1を展開するディレクトリを作成し、所有者をpostgresユーザに変更する。

[db1/db2]$ su -
[db1/db2]# mkdir /usr/local/src/slony1-1.2.1
[db1/db2]# chown postgres:postgres /usr/local/src/slony1-1.2.1

Slony-I 1.2.1のソースコードアーカイブをpgFoundryからダウンロードし、/tmpディレクトリに保存する。そして、postgresユーザになり、/usr/local/srcディレクトリでダウンロードしたアーカイブを展開する。

[db1/db2]# su - postgres
[db1/db2]$ cd /usr/local/src
[db1/db2]$ tar xjf /tmp/slony1-1.2.1-tar.bz2
[db1/db2]$ cd slony1-1.2.1

Slony-I 1.2.1のソースコードをコンパイルし、インストールする。configureスクリプトの実行時には、--with-pgconfigdirオプションでPostgreSQLの設定ファイルpg_configがあるディレクトリを指定する。

[db1/db2]$ ./configure --with-pgconfigdir=/usr/local/pgsql/bin
[db1/db2]$ make all
[db1/db2]$ make install

Slony-I 1.2.1の設定

db1サーバに検証用のtest_dbデータベースを作成し、Slony-I 1.2.1が使用する手続き言語plpgsqlをそこに登録する。そして、そのデータベースをpgbenchコマンドで初期化する。

[db1]$ createdb test_db
[db1]$ createlang plpgsql test_db
[db1]$ pgbench -i test_db

db1サーバのデータベースのスキーマをdb2サーバにコピーする。

[db2]$ createdb test_db
[db1]$ pg_dump -s test_db | psql -h db2 test_db

Slony-I 1.2.1の設定は付属のslonikコマンドで行う。設定項目が多いため、db1サーバ上で下記のシェルスクリプトをmaster_setup.shという名前で作成し、実行する。

#!/bin/sh

slonik <<_EOF_
cluster name = slony_test;
node 1 admin conninfo = 'dbname=test_db host=db1 user=postgres';
node 2 admin conninfo = 'dbname=test_db host=db2 user=postgres';
init cluster ( id=1, comment = 'Master');
table add key (node id=1, fully qualified name='public.history');
create set (id=1, origin=1, comment='All tables');
set add table (set id=1, origin=1, id=1, fully qualified name = 'public.accounts', comment='accounts');
set add table (set id=1, origin=1, id=2, fully qualified name = 'public.branches', comment='branches');
set add table (set id=1, origin=1, id=3, fully qualified name = 'public.tellers', comment='tellers');
set add table (set id=1, origin=1, id=4, fully qualified name = 'public.history', comment='history', key=serial);
store node (id=2, comment = 'Slave');
store path (server = 1, client = 2, conninfo='test_db host=db1 user=postgres');
store path (server = 2, client = 1, conninfo='test_db host=db2 user=postgres');
store listen (origin=1, provider = 1, receiver =2);
store listen (origin=2, provider = 2, receiver =1);
_EOF_
[db1]$ ./master_setup.sh

db1サーバとdb2サーバ上でslonデーモンを起動する。

[db1]$ slon slony_test "dbname=test_db user=postgres host=db1" &
[db2]$ slon slony_test "dbname=test_db user=postgres host=db2" &

db2サーバ上で下記のスクリプトをslave_setup.shという名前で作成して実行し、レプリケーションを開始する。

#!/bin/sh

slonik <<_EOF_
cluster name = slony_test;
node 1 admin conninfo = 'dbname=test_db host=db1 user=postgres';
node 2 admin conninfo = 'dbname=test_db host=db2 user=postgres';
subscribe set ( id = 1, provider = 1, receiver = 2, forward = no);
_EOF_
[db2]$ ./slave_setup.sh

2.機能

Slony-I 1.2.1の機能評価の手順を下記に示す。

レプリケーション

Slony-I 1.2.1のレプリケーション機能をpgbenchと今回開発したコンペアツールpgdiff.shを使用して検証する。

クライアント上で、db1サーバのtest_dbデータベースに対してpgbenchコマンドを実行する。

[client]$ pgbench -h db1 test_db

Slony-I 1.2.1は非同期でレプリケーションを行うため、少し間をおいてからクライアントでpgdiff.shを実行し、データベース間の差異を確認する。db1サーバとdb2サーバのデータベース間でテーブルの内容が一致している場合、各コマンドの実行後には何も表示されない。

[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol aid accounts
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol bid branches
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol tid tellers
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol aid bid tid delta history

カスケード接続

マスタとスレーブの2台の構成に、新たにスレーブを追加する。このとき、新しいスレーブは現在のスレーブに接続する。このような段階的なスレーブの接続をカスケード接続という。

db2サーバのデータベースのスキーマをdb3サーバにコピーする。

[db3]$ createdb test_db
[db2]$ pg_dump -s test_db | psql -h db3 test_db

db2サーバ上で下記のコマンドを実行し、db3ノードに関する情報をdb2サーバのslonデーモンに登録する。

[db2]$ slonik <<_EOF_
cluster name = slony_test;
node 1 admin conninfo = 'dbname=test_db host=db1 user=postgres';
node 2 admin conninfo = 'dbname=test_db host=db2 user=postgres';
node 3 admin conninfo = 'dbname=test_db host=db3 user=postgres';
subscribe set ( id = 1, provider = 1, receiver = 2, forward = yes);
store node (id=3, comment = 'Slave2');
store path (server = 2, client = 3, conninfo='dbname=test_db host=db2 user=postgres');
store path (server = 3, client = 2, conninfo='dbname=test_db host=db3 user=postgres');
store listen (origin=3, provider = 3, receiver =2);
store listen (origin=2, provider = 2, receiver =3);
_EOF_

db3サーバ上でslonデーモンを起動する。

[db3]$ slon slony_test "dbname=test_db user=postgres host=db3" &

db3サーバ上で下記のコマンドを実行し、レプリケーションを開始する。

[db3]$ slonik <<_EOF_
cluster name = slony_test;
node 2 admin conninfo = 'dbname=test_db host=db2 user=postgres';
node 3 admin conninfo = 'dbname=test_db host=db3 user=postgres';
subscribe set ( id = 1, provider = 2, receiver = 3, forward = no);
_EOF_

pgbenchとコンペアツールpgdiff.shを使用して、追加したスレーブに正常にレプリケーションされるかどうか検証する。

クライアント上で、db1サーバのtest_dbデータベースに対してpgbenchコマンドを実行する。

[client]$ pgbench -h db1 test_db

少し間をおいてからクライアントでpgdiff.shを実行し、db1サーバとdb2サーバのデータベース間の差異を確認する。db1サーバとdb2サーバのデータベース間でテーブルの内容が一致している場合、各コマンドの実行後には何も表示されない。

[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol aid accounts
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol bid branches
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol tid tellers
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol aid bid tid delta history

続いて、db2サーバとdb3サーバのデータベース間の差異を確認する。db2サーバとdb3サーバのデータベース間でテーブルの内容が一致している場合、各コマンドの実行後には何も表示されない。以上の操作で、db1サーバ、db2サーバ、db3サーバの各データベース間に差異がないこと、すなわち、追加したスレーブに正常にレプリケーションされるかどうか確認できる。

[cleint]$ ./pgdiff.sh --mhost db2 --shost db3 --database test_db --sortcol aid accounts
[cleint]$ ./pgdiff.sh --mhost db2 --shost db3 --database test_db --sortcol bid branches
[cleint]$ ./pgdiff.sh --mhost db2 --shost db3 --database test_db --sortcol tid tellers
[cleint]$ ./pgdiff.sh --mhost db2 --shost db3 --database test_db --sortcol aid bid tid delta history

スイッチオーバ

スイッチオーバを検証する。スイッチオーバとは、マスタの役割を他のノードに移行する操作のことである。

db1サーバ上で下記のコマンドを実行し、マスタの役割をdb1サーバからdb2サーバに移動する。

[db1]$ slonik <<_EOF_
cluster name = slony_test;
node 1 admin conninfo = 'dbname=test_db host=db1 user=postgres';
node 2 admin conninfo = 'dbname=test_db host=db2 user=postgres';
lock set (id = 1, origin = 1);
wait for event (origin = 1, confirmed = 2);
move set (id = 1, old origin = 1, new origin = 2);
wait for event (origin = 1, confirmed = 2);
_EOF_

pgbenchとコンペアツールpgdiff.shを使用して、マスタの役割が移動したかどうか検証する。

クライアント上で、db2サーバのtest_dbデータベースに対してpgbenchコマンドを実行する。

[client]$ pgbench -h db2 test_db

少し間をおいてからクライアントでpgdiff.shを実行し、db1サーバとdb2サーバのデータベース間の差異を確認する。db1サーバとdb2サーバのデータベース間でテーブルの内容が一致している場合、各コマンドの実行後には何も表示されない。

[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol aid accounts
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol bid branches
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol tid tellers
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol aid bid tid delta history

クライアント上で、旧マスタ(現スレーブ)のdb1サーバに対してpgbenchコマンドを実行する。スレーブは更新ができないのでエラーが出力されれば、スイッチオーバが実行されたことになる。

[client]$ pgbench -h db1 test_db
starting vacuum...ERROR:  Slony-I: Table history is replicated and cannot be modified on a subscriber node

フェイルオーバ

フェイルオーバを検証する。フェイルオーバとは障害が起きたマスタを切り離してマスタの役割を他のノードに移行する操作のことである。今回は、障害を起こさずにフェイルオーバを行う。

db2サーバ上で下記のコマンドを実行し、マスタの役割をdb1サーバからdb2サーバに移動する。

[db2]$ slonik <<_EOF_
cluster name = $CLUSTER;
node 1 admin conninfo = 'dbname=test_db host=db1 user=postgres';
node 2 admin conninfo = 'dbname=test_db host=db2 user=postgres';
failover (id = 1, backup node = 2);
_EOF_

pgbenchとコンペアツールpgdiff.shを使用して、マスタの役割が移動したかどうか検証する。

クライアント上で、db2サーバのtest_dbデータベースに対してpgbenchコマンドを実行する。

[client]$ pgbench -h db2 test_db

少し間をおいてからクライアントでpgdiff.shを実行し、db1サーバとdb2サーバのデータベース間の差異を確認する。db1サーバとdb2サーバのデータベース間でテーブルの内容が一致している場合、各コマンドの実行後には何も表示されない。フェイルオーバ後は、db1サーバが切り離されているためレプリケーションは行われていない。そのため、各コマンドの実行後に差異が表示されれば、フェイルオーバが実行されたことになる。

[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol aid accounts
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol bid branches
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol tid tellers
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol aid bid tid delta history

3.移行性

単体のPostgreSQLで運用しているアプリケーションを、Slony-I 1.2.1を用いたシステムに移行する場合に、注意すべきSQLがあるかどうか検証する。

Slony-I 1.2.1の移行性評価の手順を下記に示す。

検証前の準備

検証の前に、検証で使用するテーブルやシーケンスを用意する。

db1サーバのデータベースに各種検証用のテーブルとシーケンスを作成する。Slony-I 1.2.1は、レプリケーションを行うテーブルに主キーを用意した方が設定が容易になるため、テーブルにはすべてPRIMARY KEY制約を付ける。

[db1]$ psql test_db
test_db=# CREATE TABLE random_table (number NUMERIC PRIMARY KEY);
test_db=# CREATE TABLE timestamp_table (time TIMESTAMP PRIMARY KEY);
test_db=# CREATE TABLE serial_table (serial_number SERIAL, query_number TEXT, PRIMARY KEY(serial_number));
test_db=# CREATE TABLE seq_table (seq_number INTEGER, query_number TEXT, PRIMARY KEY(seq_number));
test_db=# CREATE SEQUENCE myseq;
test_db=# CREATE TABLE lo_table (o OID, comment TEXT, PRIMARY KEY(o));

db1サーバのデータベースのスキーマをdb2サーバにコピーする。

[db1]$ pg_dump -s test_db | psql -h db2 test_db 2> /dev/null

db1サーバ上で下記のコマンドを実行し、各種検証用のテーブルとシーケンスをレプリケーション対象として登録する。

[db1]$ slonik <<_EOF_
> cluster name = slony_test;
> node 1 admin conninfo = 'dbname=test_db host=db1 user=postgres';
> node 2 admin conninfo = 'dbname=test_db host=db2 user=postgres';
> create set ( id=2, origin=1, comment='SQL Test' );
> set add table (set id=2, origin=1, id=5, fully qualified name = 'public.random_table', comment='random_table');
> set add table (set id=2, origin=1, id=6, fully qualified name = 'public.timestamp_table', comment='timestamp_table');
> set add table (set id=2, origin=1, id=7, fully qualified name = 'public.serial_table', comment='serial_table');
> set add sequence (set id=2, origin=1, id=7, fully qualified name='public.serial_table_serial_number_seq', comment='sequence serial_table_serial_number_seq');
> set add table (set id=2, origin=1, id=8, fully qualified name = 'public.seq_table', comment='seq_table');
> set add sequence (set id=2, origin=1, id=8, fully qualified name='public.myseq', comment='sequence myseq');
> set add table (set id=2, origin=1, id=9, fully qualified name = 'public.lo_table', comment='lo_table');
> _EOF_

db2サーバ上で下記のコマンドを実行し、各種検証用のテーブルとシーケンスのレプリケーションを開始する。

[db2]$ slonik <<_EOF_
> cluster name = slony_test;
> node 1 admin conninfo = 'dbname=test_db host=db1 user=postgres';
> node 2 admin conninfo = 'dbname=test_db host=db2 user=postgres';
> subscribe set ( id = 2, provider = 1, receiver = 2, forward = no);
> _EOF_

乱数

乱数を使用したSQL文の実行結果が、どのようにレプリケーションされるか検証する。

クライアントからマスタのtest_dbデータベースに接続し、random_tableテーブルに乱数を挿入する。そして、その乱数を確認する。

[client]$ psql -h db1 test_db
test_db=# INSERT INTO random_table VALUES (random());
INSERT 0 1
test_db=# SELECT * FROM random_table;
      number
-------------------
 0.292244203990439
(1 row)

クライアントからスレーブのtest_dbデータベースに接続し、random_tableテーブルに挿入された乱数を確認する。

[client]$ psql -h db2 test_db
test_db=# SELECT * FROM random_table;
      number
-------------------
 0.292244203990439
(1 row)

マスタとスレーブで乱数が一致していることを確認する。

現在の日付と時刻

CURRENT_TIMESTAMP関数を使用したSQL文の実行結果が、どのようにレプリケーションされるか検証する。

クライアントからマスタのtest_dbデータベースに接続し、timestamp_tableテーブルに現在のタイムスタンプを挿入する。そして、そのタイムスタンプを確認する。

[client]$ psql -h db1 test_db
test_db=# INSERT INTO timestamp_table VALUES (CURRENT_TIMESTAMP);
INSERT 0 1
test_db=# SELECT * FROM timestamp_table;
            time
----------------------------
 2006-12-04 13:42:41.679315
(1 row)

クライアントからスレーブのtest_dbデータベースに接続し、timestamp_tableテーブルに挿入されたタイムスタンプを確認する。

[client]$ psql -h db2 test_db 
test_db=# INSERT INTO timestamp_table VALUES (CURRENT_TIMESTAMP);
INSERT 0 1
test_db=# SELECT * FROM timestamp_table;
            time
----------------------------
 2006-12-04 13:42:41.679315
(1 row)

マスタとスレーブでタイムスタンプが一致していることを確認する。

OID

マスタとスレーブでOIDが一致しているかどうか確認する。

クライアントからマスタのtest_dbデータベースに接続し、branchesテーブルの1行目のOIDを確認する。

[client]$ psql -h db1 test_db
test_db=# SELECT oid, * FROM branches;
  oid  | bid | bbalance | filler
-------+-----+----------+--------
 16396 |   1 |        0 |
(1 row)

クライアントからスレーブのtest_dbデータベースに接続し、branchesテーブルの1行目のOIDを確認する。

[client]$ psql -h db2 test_db
test_db=# SELECT oid, * FROM branches;
  oid   | bid | bbalance | filler
--------+-----+----------+--------
 216749 |   1 |        0 |
(1 row)

通常、マスタとスレーブでOIDは一致しない。

SERIAL型

SERIAL型を使用したSQL文の実行結果が、どのようにレプリケーションされるか検証する。検証は簡単なシェルスクリプトでほぼ同時に100個のデータを挿入し、マスタとスレーブでSERIAL型の値にずれが出ないか確認する。

下記のシェルスクリプトをクライアント上で実行する。

[client]$ for (( i = 1; i <= 100; i++)); do {
> psql -h db1 test_db -c "INSERT INTO serial_table(query_number) VALUES ('Query$i')" &
> }; done;
INSERT 0 1
INSERT 0 1
(以下省略)

クライアント上でpgdiff.shを実行し、マスタとスレーブのserial_tableテーブルの内容が一致していることを確認する。

[client]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol seq_number serial_table

シーケンス

SEQUENCEを使用したSQL文の実行結果が、どのようにレプリケーションされるか検証する。検証は簡単なシェルスクリプトでほぼ同時に100個のデータを挿入し、マスタとスレーブでSEQUENCEの値にずれが出ないか確認する。

下記のシェルスクリプトをクライアント上で実行する。

[client]$ for (( i = 1; i <= 100; i++)); do {
> psql -h db1 test_db -c "INSERT INTO seq_table VALUES (nextval('myseq'), 'Query$i')" &
> }; done;
INSERT 0 1
INSERT 0 1
(以下省略)

クライアント上でpgdiff.shを実行し、マスタとスレーブのseq_tableテーブルの内容が一致していることを確認する。

[client]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol seq_number seq_table

トランザクションID

マスタとスレーブでトランザクションIDが一致しているかどうか確認する。

クライアントからマスタのtest_dbデータベースに接続し、SEQUENCEの項で作成したseq_tableテーブルの各行のトランザクションIDを確認する。

[client]$ psql -h db1 teest_db
test_db=# SELECT xmin, xmax, * FROM seq_table;
 xmin  | xmax | seq_number | query_number
-------+------+------------+--------------
 25503 |    0 |          1 | Query1
(以下省略)

クライアントからスレーブのtest_dbデータベースに接続し、SEQUENCEの項で作成したseq_tableテーブルの各行のトランザクションIDを確認する。

[client]$ psql -h db2 teest_db
test_db=# SELECT xmin, xmax, * FROM seq_table;
 xmin  | xmax | seq_number | query_number
-------+------+------------+--------------
 21675 |    0 |          1 | Query1
(以下省略)

通常、マスタとスレーブでトランザクションIDは一致しない。

DDL操作

CREATE DATABASE

CREATE DATABASEの実行結果がレプリケーションされるか検証する。

クライアントからdb1サーバに接続し、test_db2データベースを作成する。

[client]$ psql -h db1
postgres=# CREATE DATABASE test_db2;
CREATE DATABASE
postgres=# \l
        List of databases
   Name    |  Owner   | Encoding
-----------+----------+----------
 postgres  | postgres | EUC_JP
 template0 | postgres | EUC_JP
 template1 | postgres | EUC_JP
 test_db   | postgres | EUC_JP
 test_db2  | postgres | EUC_JP
(5 rows)

クライアントからdb2サーバに接続し、test_db2データベースが作成されているか確認する。

[client]$ psql -h db2
postgres=# \l
        List of databases
   Name    |  Owner   | Encoding
-----------+----------+----------
 postgres  | postgres | EUC_JP
 template0 | postgres | EUC_JP
 template1 | postgres | EUC_JP
 test_db   | postgres | EUC_JP
(4 rows)
CREATE USER

CREATE USERの実行結果がレプリケーションされるか検証する。

クライアントからdb1サーバに接続し、test_userユーザを作成する。

[client]$ psql -h db1
postgres=# CREATE USER test_user;
CREATE ROLE
postgres=# \du
                               List of roles
 Role name | Superuser | Create role | Create DB | Connections | Member of
-----------+-----------+-------------+-----------+-------------+-----------
 postgres  | yes       | yes         | yes       | no limit    |
 test_user | no        | no          | no        | no limit    |
(2 rows)

クライアントからdb2サーバに接続し、test_userユーザが作成されているか確認する。

[client]$ psql -h db2
 postgres=# \du
                                List of roles
  Role name | Superuser | Create role | Create DB | Connections | Member of
 -----------+-----------+-------------+-----------+-------------+-----------
  postgres  | yes       | yes         | yes       | no limit    |
 (1 row)
CREATE GROUP

CREATE GROUPの実行結果がレプリケーションされるか検証する。

クライアントからdb1サーバに接続し、test_groupグループを作成する。

[client]$ psql -h db1
postgres=# CREATE GROUP test_group;
CREATE ROLE
postgres=# \dg
                               List of roles
 Role name  | Superuser | Create role | Create DB | Connections | Member of
------------+-----------+-------------+-----------+-------------+-----------
 postgres   | yes       | yes         | yes       | no limit    |
 test_group | no        | no          | no        | no limit    |
(2 rows)

クライアントからdb2サーバに接続し、test_userグループが作成されているか確認する。

[client]$ psql -h db2
postgres=# \dg
                               List of roles
 Role name | Superuser | Create role | Create DB | Connections | Member of
-----------+-----------+-------------+-----------+-------------+-----------
 postgres  | yes       | yes         | yes       | no limit    |
(1 row)
CREATE SCHEMA

CREATE SCHEMAの実行結果がレプリケーションされるか検証する。

クライアントからdb1サーバに接続し、test_schemaスキーマを作成する。

[client]$ psql -h db1
postgres=# CREATE SCHEMA test_schema;
CREATE SCHEMA
postgres=# \dn
        List of schemas
        Name        |  Owner
--------------------+----------
 information_schema | postgres
 pg_catalog         | postgres
 pg_toast           | postgres
 public             | postgres
 test_schema        | postgres
(5 rows)

クライアントからdb2サーバに接続し、test_schemaスキーマが作成されているか確認する。

[client]$ psql -h db2
postgres=# \dn
        List of schemas
        Name        |  Owner
--------------------+----------
 information_schema | postgres
 pg_catalog         | postgres
 pg_toast           | postgres
 public             | postgres
(4 rows)
CREATE TABLE

CREATE TABLEの実行結果がレプリケーションされるか検証する。

クライアントからdb1サーバに接続し、test_tableテーブルを作成する。

[client]$ psql -h db1
postgres=# CREATE TABLE test_table(i INTEGER);
CREATE TABLE
postgres=# \dt
           List of relations
 Schema |    Name    | Type  |  Owner
--------+------------+-------+----------
 public | test_table | table | postgres
(1 row)

クライアントからdb2サーバに接続し、test_tableテーブルが作成されているか確認する。

[client]$ psql -h db2
postgres=# \dt
No relations found.
CREATE TABLE AS

CREATE TABLE ASの実行結果がレプリケーションされるか検証する。

クライアントからdb1サーバに接続し、test_table2テーブルを作成する。

[client]$ psql -h db1
postgres=# CREATE TABLE test_table(i INTEGER);
CREATE TABLE
postgres=# CREATE TABLE test_table2 AS SELECT * FROM test_table;
SELECT
postgres=# \dt
            List of relations
 Schema |    Name     | Type  |  Owner
--------+-------------+-------+----------
 public | test_table  | table | postgres
 public | test_table2 | table | postgres
(2 rows)

クライアントからdb2サーバに接続し、test_table2テーブルが作成されているか確認する。

[client]$ psql -h db2
postgres=# \dt
No relations found.
CREATE TEMP TABLE

CREATE TEMP TABLEの実行結果がレプリケーションされるか検証する。

クライアントからdb1サーバに接続し、test_temptableテーブルを作成する。

[client]$ psql -h db1
postgres=# CREATE TABLE test_table(i INTEGER);
CREATE TABLE
postgres=# CREATE TEMP TABLE test_temptable AS SELECT * FROM test_table;
SELECT
postgres=# \dt
             List of relations
  Schema   |      Name      | Type  |  Owner
-----------+----------------+-------+----------
 pg_temp_7 | test_temptable | table | postgres
 public    | test_table     | table | postgres
(2 rows)

クライアントからdb2サーバに接続し、test_temptableテーブルが作成されているか確認する。

[client]$ psql -h db2
postgres=# \dt
No relations found.
CREATE TABLESPACE

CREATE TABLESPACEの実行結果がレプリケーションされるか検証する。

クライアントからdb1サーバに接続し、test_tablespaceテーブルスペースを作成する。

[db1/db2]$ mkdir /tmp/test_tablespace
[client]$ psql -h db1
postgres=# CREATE TABLESPACE  test_tablespace LOCATION '/tmp/test_tablespace';
CREATE TABLESPACE
postgres=# \db
                List of tablespaces
      Name       |  Owner   |       Location
-----------------+----------+----------------------
 pg_default      | postgres |
 pg_global       | postgres |
 test_tablespace | postgres | /tmp/test_tablespace
(3 rows)

クライアントからdb2サーバに接続し、test_tablespaceテーブルスペースが作成されているか確認する。

[client]$ psql -h db2
postgres=# \db
       List of tablespaces
    Name    |  Owner   | Location
------------+----------+----------
 pg_default | postgres |
 pg_global  | postgres |
(2 rows)
CREATE SEQUENCE

CREATE SEQUENCEの実行結果がレプリケーションされるか検証する。

クライアントからdb1サーバに接続し、test_seqシーケンスを作成する。

[client]$ psql -h db1
postgres=# CREATE SEQUENCE test_seq;
CREATE SEQUENCE
postgres=# \ds
            List of relations
 Schema |   Name   |   Type   |  Owner
--------+----------+----------+----------
 public | test_seq | sequence | postgres
(1 row)

クライアントからdb2サーバに接続し、test_seqシーケンスが作成されているか確認する。

[client]$ psql -h db2
postgres=# \ds
No relations found.
CREATE DOMAIN

CREATE DOMAINの実行結果がレプリケーションされるか検証する。

クライアントからdb1サーバに接続し、test_domainドメインを作成する。

[client]$ psql -h db1
postgres=# CREATE DOMAIN post_code AS CHARACTER (8)
postgres-# CONSTRAINT post_code_must_be_7_digits
postgres-# CHECK (VALUE ~ '~\\d{3}-\\d[4]$');
CREATE DOMAIN
postgres=# \dD
                                     List of domains
 Schema |   Name    |     Type     | Modifier |                  Check          
--------+-----------+--------------+----------+------------------------------------------
 public | post_code | character(8) |          | CHECK (VALUE ~ E'~\\d{3}-\\d[4]$'::text)
(1 row)

クライアントからdb2サーバに接続し、test_domainドメインが作成されているか確認する。

[client]$ psql -h db2
postgres=# \dD
             List of domains
 Schema | Name | Type | Modifier | Check
--------+------+------+----------+-------
(0 rows)
CREATE VIEW

CREATE VIEWの実行結果がレプリケーションされるか検証する。

クライアントからdb1サーバに接続し、test_viewヴューを作成する。

[client]$ psql -h db1
postgres=# CREATE VIEW test_view AS SELECT i AS number FROM test_table;
CREATE VIEW
postgres=# \dv
          List of relations
 Schema |   Name    | Type |  Owner
--------+-----------+------+----------
 public | test_view | view | postgres
(1 row)

クライアントからdb2サーバに接続し、test_viewヴューが作成されているか確認する。

[client]$ psql -h db2
postgres=# \dv
No relations found.
CREATE INDEX

CREATE INDEXの実行結果がレプリケーションされるか検証する。

クライアントからdb1サーバに接続し、test_indexインデックスを作成する。

[client]$ psql -h db1
postgres=# CREATE TABLE test_table(i INTEGER);
CREATE TABLE
postgres=# CREATE UNIQUE INDEX test_idx on test_table (i);
CREATE INDEX
postgres=# \di
                 List of relations
 Schema |   Name   | Type  |  Owner   |   Table
--------+----------+-------+----------+------------
 public | test_idx | index | postgres | test_table
(1 row)

クライアントからdb2サーバに接続し、test_indexインデックスが作成されているか確認する。

[client]$ psql -h db2
postgres=# \di
No relations found.
CREATE RULE

CREATE RULEの実行結果がレプリケーションされるか検証する。

クライアントからdb1サーバに接続し、test_table_logテーブルとtest_ruleルールを作成する。

[client]$ psql -h db1
postgres=# CREATE TABLE test_table_log (user_name TEXT, acttime TIMESTAMP);
CREATE TABLE
postgres=# CREATE RULE test_rule AS ON INSERT TO test_table
postgres-# DO INSERT INTO test_table_log VALUES (CURRENT_USER, CURRENT_TIMESTAMP);
CREATE RULE
postgres=# INSERT INTO test_table VALUES (1);
INSERT 0 1
postgres=# SELECT * FROM pg_rules WHERE tablename = 'test_table';
-[ RECORD 1 ]-----------------------------------------------------------------------------
--------------------------------------------------------
schemaname | public
tablename  | test_table
rulename   | test_rule
definition | CREATE RULE test_rule AS ON INSERT TO test_table DO INSERT INTO 
             test_table_log (user_name, acttime) VALUES ("current_user"(), now());
postgres=# SELECT * FROM test_table_log;
-[ RECORD 1 ]-------------------------
user_name | postgres
acttime   | 2006-12-08 13:38:55.903292

クライアントからdb2サーバに接続し、test_table_logテーブルとtest_ruleルールが作成されているか確認する。

[client]$ psql -h db2
postgres=# SELECT * FROM pg_rules WHERE tablename = 'test_table';
 schemaname | tablename | rulename | definition
------------+-----------+----------+------------
(0 rows)
postgres=# SELECT * FROM test_table_log;
ERROR:  relation "test_table_log" does not exist
ERROR:  relation "test_table_log" does not exist
CREATE LANGUAGE

CREATE LANGUAGEの実行結果がレプリケーションされるか検証する。

クライアントからdb1サーバに接続し、plpgsql言語を登録する。

[client]$ psql -h db1
postgres=# CREATE LANGUAGE plpgsql;
CREATE LANGUAGE
postgres=# SELECT * FROM pg_language WHERE lanname = 'plpgsql';
 lanname | lanispl | lanpltrusted | lanplcallfoid | lanvalidator | lanacl
---------+---------+--------------+---------------+--------------+--------
 plpgsql | t       | t            |         16767 |        16768 |
(1 row)

クライアントからdb2サーバに接続し、plpgsql言語が登録されているか確認する。

[client]$ psql -h db2
postgres=# SELECT * FROM pg_language WHERE lanname = 'plpgsql';
 lanname | lanispl | lanpltrusted | lanplcallfoid | lanvalidator | lanacl
---------+---------+--------------+---------------+--------------+--------
(0 rows)
CREATE FUNCTION

CREATE FUNCTIONの実行結果がレプリケーションされるか検証する。

クライアントからdb1サーバに接続し、log_function関数を作成する。

[client]$ psql -h db1
postgres=# CREATE FUNCTION log_function() RETURNS TRIGGER AS '
postgres'#   BEGIN
postgres'#     INSERT INTO test_table_log VALUES (
postgres'#     CURRENT_USER, CURRENT_TIMESTAMP);
postgres'#   RETURN NEW;
postgres'#   END;
postgres'# ' LANGUAGE plpgsql;
CREATE FUNCTION
postgres=# \df log_function
                       List of functions
 Schema |     Name     | Result data type | Argument data types
--------+--------------+------------------+---------------------
 public | log_function | "trigger"        |
(1 row)

クライアントからdb2サーバに接続し、log_function関数が作成されているか確認する。

[client]$ psql -h db2
postgres=# \df log_function
                   List of functions
 Schema | Name | Result data type | Argument data types
--------+------+------------------+---------------------
(0 rows)
CREATE TRIGGER

CREATE TRIGGERの実行結果がレプリケーションされるか検証する。

クライアントからdb1サーバに接続し、test_triggerトリガを作成する。

[client]$ psql -h db1
postgres=# CREATE TRIGGER test_trigger AFTER UPDATE ON test_table FOR EACH ROW EXECUTE PROCEDURE log_function();
CREATE TRIGGER
postgres=# SELECT * FROM pg_trigger WHERE tgname = 'test_trigger';
-[ RECORD 1 ]--+-------------
tgrelid        | 16750
tgname         | test_trigger
tgfoid         | 16772
tgtype         | 17
tgenabled      | t
tgisconstraint | f
tgconstrname   |
tgconstrrelid  | 0
tgdeferrable   | f
tginitdeferred | f
tgnargs        | 0
tgattr         |
tgargs         |

クライアントからdb2サーバに接続し、log_function関数が作成されているか確認する。

[client]$ psql -h db2
postgres=# SELECT * FROM pg_trigger WHERE tgname = 'test_trigger';
(No rows)

ラージオブジェクト

ラージオブジェクトがレプリケーションされるか検証する。

クライアントからマスタのtest_dbデータベースに接続し、tmpディレクトリにあるPostgreSQL 8.1.5のソースコードアーカイブを、ラージオブジェクトとして登録する。そして、ラージオブジェクトの登録状況とそれが取得できることを確認する。

[client]$ psql -h db1 test_db
test_db=# \lo_import '/tmp/postgresql-8.1.5.tar.gz' 'PostgreSQL archive'
lo_import 16745
test_db=# \lo_list
    Large objects
  ID   | Description
-------+-------------
 16745 | ls command
(1 row)
test_db=# \lo_export 16745 '/tmp/postgresql-8.1.5.tar.gz'
lo_export

クライアントからスレーブのtest_dbデータベースに接続し、ラージオブジェクトの登録状況とそれが取得できるか確認する。取得時はラージオブジェクトのOIDは登録時のOIDを使用する。

[client]$ psql -h db2 test_db
test_db=# \lo_list
  Large objects
 ID | Description
----+-------------
(0 rows)
test_db=# \lo_export 16745 '/tmp/ls_command'
could not open large object 16745

4.耐障害性

slonプロセス障害

マスタの障害発生

クライアント上で下記のコマンドを実行する。

[client]$ pgbench -h db1 -c 10 -t 1000 test_db

pgbenchの実行中にdb1サーバ上で下記のコマンドを実行し、slonプロセスを強制終了する。そして、その後もpgbenchが動き続け、正常終了することを確認する。

[db1]$ killall -INT slon

pgbenchが終了後、クライアント上でpgdiff.shを実行し、マスタとスレーブのtest_dbデータベースの各テーブルの内容に差異があることを確認する。

[client]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol aid accounts
[client]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol bid branches
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol tid tellers
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol aid bid tid delta history
マスタの障害復旧

db1サーバ上でslonを起動する。

[db1]$ slon slony_test "dbname=test_db user=postgres host=db1" &

少し間をおいてからクライアント上でpgdiff.shを実行し、マスタとスレーブのtest_dbデータベースの各テーブルの内容に差異がないことを確認する。

[client]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol aid accounts
[client]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol bid branches
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol tid tellers
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol aid bid tid delta history
スレーブの障害発生

クライアント上で下記のコマンドを実行する。

[client]$ pgbench -h db1 -c 10 -t 1000 test_db

pgbenchの実行中にdb2サーバ上で下記のコマンドを実行し、slonプロセスを強制終了する。そして、その後もpgbenchが動き続け、正常終了することを確認する。

[db2]$ killall -INT slon

pgbenchが終了後、クライアント上でpgdiff.shを実行し、マスタとスレーブのtest_dbデータベースの各テーブルの内容に差異があることを確認する。

[client]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol aid accounts
[client]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol bid branches
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol tid tellers
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol aid bid tid delta history
スレーブの障害復旧

db2サーバ上でslonを起動する。

[db2]$ slon slony_test "dbname=test_db user=postgres host=db2" &

少し間をおいてからクライアント上でpgdiff.shを実行し、マスタとスレーブのtest_dbデータベースの各テーブルの内容に差異がないことを確認する。

[client]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol aid accounts
[client]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol bid branches
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol tid tellers
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol aid bid tid delta history

postmasterプロセスの障害

マスタの障害発生

クライアント上で下記のコマンドを実行する。

[client]$ pgbench -h db1 -c 10 -t 1000 test_db

pgbenchの実行中にdb1サーバ上で下記のコマンドを実行し、postmasterプロセスを強制終了する。そして、pgbenchも同時に終了することを確認する。

[db1]$ killall -INT postmaster

db1サーバ上でpostmasterを起動する。

[db1]$ pg_ctl -w start

クライアント上でpgdiff.shを実行し、マスタとスレーブのtest_dbデータベースの各テーブルの内容に差異があることを確認する。

[client]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol aid accounts
[client]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol bid branches
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol tid tellers
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol aid bid tid delta history
マスタの障害復旧

db1サーバ上でslonを起動する。

[db1]$ slon slony_test "dbname=test_db user=postgres host=db2" &

少し間をおいてからクライアント上でpgdiff.shを実行し、マスタとスレーブのtest_dbデータベースの各テーブルの内容に差異がないことを確認する。

[client]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol aid accounts
[client]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol bid branches
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol tid tellers
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol aid bid tid delta history
スレーブの障害発生

クライアント上で下記のコマンドを実行する。

[client]$ pgbench -h db1 -c 10 -t 1000 test_db

pgbenchの実行中にdb2サーバ上で下記のコマンドを実行し、postmasterプロセスを強制終了する。そして、その後もpgbenchが動き続け、正常終了することを確認する。

[db2]$ killall -INT postmaster

pgbenchが終了後、db2サーバ上でpostmasterを起動する。

[db2]$ pg_ctl -w start

クライアント上でpgdiff.shを実行し、マスタとスレーブのtest_dbデータベースの各テーブルの内容に差異があることを確認する。

[client]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol aid accounts
[client]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol bid branches
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol tid tellers
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol aid bid tid delta history
スレーブの障害復旧

db2サーバ上でpostmasterを起動する。

[db2]$ pg_ctl -w start

db2サーバ上でslonを起動する。

[db2]$ slon slony_test "dbname=test_db user=postgres host=db2" &

少し間をおいてからクライアント上でpgdiff.shを実行し、マスタとスレーブのtest_dbデータベースの各テーブルの内容に差異がないことを確認する。

[client]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol aid accounts
[client]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol bid branches
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol tid tellers
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol aid bid tid delta history

ネットワーク障害

マスタの障害発生

クライアント上で下記のコマンドを実行する。

[client]$ pgbench -h db1 -c 10 -t 1000 test_db

pgbenchの実行中にdb1サーバ上で下記のコマンドを実行し、ネットワークインタフェースをダウンさせる。今回はdb1サーバをリモートで操作しているため、atコマンドを使い5分後にネットワークインタフェースをアップする設定も行う。そして、その後もpgbenchが動き続け、正常終了することを確認する。

[db1]$ su -
[db1]# at now + 5 minutes
at> ifconfig eth0 up
at> 
job 3 at 2006-11-20 16:28
[db1]# ifconfig eth0 down
[db1]# exit
マスタの障害復旧

ネットワークの復旧直後と少し間をおいた後にクライアント上でpgdiff.shを実行し、マスタとスレーブのtest_dbデータベースの各テーブルの内容に差異があるか確認する。復旧直後は差異があり、少し間をおいた後は差異がないのが正常である。

[client]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol aid accounts
[client]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol bid branches
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol tid tellers
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol aid bid tid delta history
スレーブの障害発生

クライアント上で下記のコマンドを実行する。

[client]$ pgbench -h db1 -c 10 -t 1000 test_db

pgbenchの実行中にdb2サーバ上で下記のコマンドを実行し、ネットワークインタフェースをダウンさせる。今回はdb2サーバをリモートで操作しているため、atコマンドを使い5分後にネットワークインタフェースをアップする設定も行う。そして、その後もpgbenchが動き続け、正常終了することを確認する。

[db2]$ su -
[db2]# at now + 5 minutes
at> ifconfig eth0 up
at> 
job 3 at 2006-11-20 17:51
[db2]# ifconfig eth0 down
[db2]# exit
スレーブの障害復旧

ネットワークの復旧直後と少し間をおいた後にクライアント上でpgdiff.shを実行し、マスタとスレーブのtest_dbデータベースの各テーブルの内容に差異があるか確認する。復旧直後は差異があり、少し間をおいた後は差異がないのが正常である。

[client]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol aid accounts
[client]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol bid branches
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol tid tellers
[cleint]$ ./pgdiff.sh --mhost db1 --shost db2 --database test_db --sortcol aid bid tid delta history