Postgresqlレプリケーション Slony-I構築メモ
ここではPostgreSQLのレプリケーションツール、Slony-Iについての構築と運用方法をメモしておきます。
Slony-Iについて
- 特徴
- マスタースレイブ型のレプリケーションシステム
- 同期対象のテーブルについては、マスタのみ更新可能。スレーブは参照のみ。
- 同期対象外のテーブルはどのノードでもフルアクセス可能。
- カスケード構成可能
- テーブル単位でレプリケーションの指定が可能
- プライマリキーの無いテーブルのレプリケーションも可能(注意点が多いので、全力で回避するほうがいいです)
- 同期されるのは、insert,update,deleteのみ
- DDLは同期されない(同期対象のテーブルに流すと、DDLによっては同期が壊れる)
- レプリケーション単位をset、setに含まれるDBをnodeと呼ぶ
- レプリケーション構成は、set単位で管理される
- メリット
- 異なるバージョンのPostgreSQLのDBの同期が可能(8.3系 <-> 9.0系でもOK!)
- スレーブノードを増やしてもマスタノードにほとんど負荷はかからない
- 運用中にレプリケーションを構築できる。しかも同期が速い、マスタノードの負荷が低い
- 運用中にレプリケーションの構成を変更することができる
- 運用中にマスタノードを変更することができる(switch over)
- 手軽にレプリケーションデータの再同期を行える
- ノードごとにインデックスやプラグインを設定することができる
- 複数の異なるDBのテーブルを混ぜあわせたDBを構築することができる
- デメリット
- 構築がめんどくさい
- 運用するには、slonyコマンドの理解が必要
- カラム、テーブルの追加、削除は専用のコマンドや手順が必要。
- Slony-Iのバージョンが異なると、同期が行えない。(マイナーバージョン違いでもだめな事が多かった・・・)
個人的な感想ですが、PostgreSQLのメジャーアップデート時のデータ移行や、slaveDBに(全文)検索機能を構築するのに便利です。
ただ、テーブルの追加や、vacuum fullなどの運用がめんどくさい。。。
さらに、プライマリキーの無いテーブルの同期は注意が必要。
ノード毎にDBの構成を変える必要がなければ、PostgreSQL9.0.2以降のストリーミングレプリケーションを使うほうがいいです。
構築
インストール
Slony-I 1.2系の最新版のslony1-1.2.21をインストールします。
PostgreSQLは既にインストール済みの前提です。
cd /usr/local/src wget http://main.slony.info/downloads/1.2/source/slony1-1.2.21.tar.bz2 tar xvfj slony1-1.2.21.tar.bz2 cd slony1-1.2.21 ./configure \ --prefix=/usr/local/slony \ --with-pgconfigdir=/usr/local/pgsql/bin \ --with-perltools make su make install exit
- configureの指定
| --prefix | インストールディレクトリ指定 |
| --with-pgconfigdir | PostgreSQLのpg_configコマンドのディレクトリ |
| --with-perltools | 追加で、slony管理スクリプトのインストールする |
また、Slony-IのログのローテートでApacheのrotatelogsを使うため、必要ならApacheもあわせてインストールしてください。(インストールオプションは何でも大丈夫です)
レプリケーション構成
レプリケーション構築
- 大まかな手順
(1)設定ファイル作成
(2)レプリケーションスキーマ作成
(3)マスタDBにレプリケーション構成作成
(4)slonyプロセス起動
(5)スレーブDBにレプリケーション構成作成(購読設定)
(6)同期確認
(1)設定ファイルの準備
Slony設定ファイル/usr/local/slony/etc/slon_tools_sample.confを編集します。
/usr/local/slony/etc/slon_tools.conf-sampleをコピーして作成します。
/usr/local/slony/etc/slon_tools_sample.conf
# $Id: slon_tools.conf-sample,v 1.7.2.2 2009-08-17 22:21:43 devrim Exp $
# Author: Christopher Browne
# Copyright 2004-2009 Afilias Canada
# Revised extensively by Steve Simms
# Keeping the following three lines for backwards compatibility in
# case this gets incorporated into a 1.0.6 release.
#
# TODO: The scripts should check for an environment variable
# containing the location of a configuration file. That would
# simplify this configuration file and allow Slony-I tools to still work
# in situations where it doesn't exist.
#
if ($ENV{"SLONYNODES"}) {
require $ENV{"SLONYNODES"};
} else {
# The name of the replication cluster. This will be used to
# create a schema named _$CLUSTER_NAME in the database which will
# contain Slony-related data.
$CLUSTER_NAME = 'replication_sample';
# The directory where Slony should record log messages. This
# directory will need to be writable by the user that invokes
# Slony.
$LOGDIR = '/var/log/slony1';
# (Optional) If you would like to use Apache's rotatelogs tool to
# manage log output, uncomment the following line and ensure that
# it points to the executable.
#
# $APACHE_ROTATOR = '/usr/local/apache/bin/rotatelogs';
# SYNC check interval (slon -s option)
# $SYNC_CHECK_INTERVAL = 1000;
# Which node is the default master for all sets?
$MASTERNODE = 1;
# Include add_node lines for each node in the cluster. Be sure to
# use host names that will resolve properly on all nodes
# (i.e. only use 'localhost' if all nodes are on the same host).
# Also, note that the user must be a superuser account.
add_node(node => 1,
host => '192.168.0.100',
dbname => 'testdb',
port => 5432,
user => 'postgres',
password => '');
add_node(node => 2,
host => '192.168.0.101',
dbname => 'testdb',
port => 5432,
user => 'postgres',
password => '');
add_node(node => 3,
host => '192.168.0.102',
dbname => 'testdb',
port => 5432,
user => 'postgres',
password => '');
# If the node should only receive event notifications from a
# single node (e.g. if it can't access the other nodes), you can
# specify a single parent. The downside to this approach is that
}
# The $SLONY_SETS variable contains information about all of the sets
# in your cluster.
$SLONY_SETS = {
# A unique name for the set
"set_sample" => {
# The set_id, also unique
"set_id" => 1,
# Uncomment the following line to change the origin
# (a.k.a. master) for the set. The default is $MASTERNODE.
#
"origin" => 1,
# If this is set to 1, table and sequence names will be folded to lower-case
# to match the way that PostgreSQL handles unquoted names.
# For example, CREATE TABLE ACCOUNT(...) actually turns into CREATE TABLE account(...);
# unless you put quotes around the table name
# Slony always quotes object names, so you may get a mis-match between the table-name
# as PostgreSQL understands it, and as Slony represents it.
# default value is 0
#
# foldCase => 0,
# The first ID to use for tables and sequences that are added
# to the replication cluster. This must be unique across the
# cluster.
#
# TODO: This should be determined automatically, which can be
# done fairly easily in most cases using psql. create_set
# should derive it, and give an option to override it with a
# specific value.
"table_id" => 1000,
"sequence_id" => 1000,
# This array contains a list of tables that already have
# primary keys.
"pkeyedtables" => [
'table1',
'table2',
],
# For tables that have unique not null keys, but no primary
# key, enter their names and indexes here.
"keyedtables" => {},
# If a table does not have a suitable key or set of keys that
# can act as a primary key, Slony can add one.
#
# Note: The Slony development team does not recomment this
# approach -- you should create your own primary keys instead.
"serialtables" => [],
# Sequences that need to be replicated should be entered here.
"sequences" => ['table1_seq',
'table2_seq',
],
},
};
# Keeping the following three lines for backwards compatibility in
# case this gets incorporated into a 1.0.6 release.
#
# TODO: The scripts should check for an environment variable
# containing the location of a configuration file. That would
# simplify this configuration file and allow Slony tools to still work
# in situations where it doesn't exist.
#
if ($ENV{"SLONYSET"}) {
require $ENV{"SLONYSET"};
}
# Please do not add or change anything below this point.
1;
| CLUSTER_NAME | slonyのレプリケーションクラスタ名。slony操作は、クラスタに対してsetやnodeを指定して実行します。また、管理スキーマはここで指定した_replication_sampleといった名前になります。 |
| LOGDIR | ログ格納ディレクトリ |
| APACHE_ROTATOR | ログローテート |
| MASTERNODE | マスタノード。node番号を指定します。 |
| add_node | ノード設定。node(ノード番号)毎にDBを割り当てます。 |
| SLONY_SETS | set設定。 |
| set_id | セット番号 |
| origin | そのセットのマスタnode番号。MASTERNODEと同じなら必要ない |
| table_id | set内で管理するテーブルに割り当てるIDの最初の番号。以降、連番になる。レプリケーション単位でユニークにする必要がある。 |
| sequence_id | set内で管理するシーケンスに割り当てるIDの最初の番号。以降、連番になる。レプリケーション単位でユニークにする必要がある。 |
| pkeyedtables | 同期対象とするテーブルのうちプライマリキーを持つもののリストを設定する |
| keyedtables | 同期対象とするテーブルのうち、プライマリキーを持たず、レコードを特定するユニークなキーを持つもののリストを設定する |
| serialtables | 同期対象とするテーブルのうちレコードを特定するユニークなキーを持たないもののリストを設定する |
| sequences | pkeyedtables、keyedtablesのキーがシーケンスのとき、そのシーケンスを指定する |
(2)レプリケーションスキーマ作成
初期設定。Slonyのレプリケーション管理スキーマがslon_tools_sample.confで
指定した全てのノードのDBで作成されます
これは、マスタノードで実行します。
- at 192.168.0.100
cd /usr/local/slony/bin/ slonik_init_cluster --config=../etc/slon_tools_sample.conf | slonik
生成されるスクリプト
# INIT CLUSTER cluster name = replication_sample; node 1 admin conninfo='host=192.168.0.100 dbname=testdb user=postgres port=5432'; node 2 admin conninfo='host=192.168.0.101 dbname=testdb user=postgres port=5432'; node 3 admin conninfo='host=192.168.0.102 dbname=testdb user=postgres port=5432'; init cluster (id = 1, comment = 'Node 1 - testdb@192.168.0.100'); # STORE NODE store node (id = 2, event node = 1, comment = 'Node 2 - testdb@192.168.0.101'); store node (id = 3, event node = 1, comment = 'Node 3 - testdb@192.168.0.102'); echo 'Set up replication nodes'; # STORE PATH echo 'Next: configure paths for each node/origin'; store path (server = 1, client = 2, conninfo = 'host=192.168.0.100 dbname=testdb user=postgres port=5432'); store path (server = 1, client = 3, conninfo = 'host=192.168.0.100 dbname=testdb user=postgres port=5432'); store path (server = 2, client = 1, conninfo = 'host=192.168.0.101 dbname=testdb user=postgres port=5432'); store path (server = 2, client = 3, conninfo = 'host=192.168.0.101 dbname=testdb user=postgres port=5432'); store path (server = 3, client = 1, conninfo = 'host=192.168.0.102 dbname=testdb user=postgres port=5432'); store path (server = 3, client = 2, conninfo = 'host=192.168.0.102 dbname=testdb user=postgres port=5432'); echo 'Replication nodes prepared'; echo 'Please start a slon replication daemon for each node';
(3)マスタDBにレプリケーション構成作成
レプリケーションを行うテーブルのセット情報の設定。
セット番号はslon_tools_sample.confで作成したものを使用します。
これは、マスタノードで実行します。
- at 192.168.0.100
slonik_create_set --config=../etc/slon_tools_sample.conf set1 | slonik
生成されるスクリプト
cluster name = replication_sample;
node 1 admin conninfo='host=192.168.0.100 dbname=testdb user=postgres port=5432';
node 2 admin conninfo='host=192.168.0.101 dbname=testdb user=postgres port=5432';
node 3 admin conninfo='host=192.168.0.102 dbname=testdb user=postgres port=5432';
# TABLE ADD KEY
# CREATE SET
try {
create set (id = 1, origin = 1, comment = 'Set 1 for replication_sample');
} on error {
echo 'Could not create subscription set 1 for replication_sample!';
exit -1;
}
# SET ADD TABLE
echo 'Subscription set 1 created';
echo 'Adding tables to the subscription set';
set add table (set id = 1, origin = 1, id = 1000,
full qualified name = 'public.table1',
comment = 'Table public.table1 with primary key');
echo 'Add primary keyed table public.table1';
set add table (set id = 1, origin = 1, id = 1001,
full qualified name = 'public.table2',
comment = 'Table public.table2 with primary key');
echo 'Add primary keyed table public.table2';
# SET ADD SEQUENCE
echo 'Adding sequences to the subscription set';
set add sequence (set id = 1, origin = 1, id = 1000,
full qualified name = 'public.table1_seq',
comment = 'Sequence public.table1_seq');
echo 'Add sequence public.table1_seq';
set add sequence (set id = 1, origin = 1, id = 1001,
full qualified name = 'public.table2_seq',
comment = 'Sequence public.table2_seq');
echo 'Add sequence public.table2_seq';
echo 'All tables added';(4)slonyプロセス起動
slony起動。slon_tools_sample.confでしていたノード番号を指定します。
格サーバで実行します。
- at 192.168.0.100
slon_start --config=../etc/slon_tools_sample.conf node1
- at 192.168.0.101
slon_start --config=../etc/slon_tools_sample.conf node2
- at 192.168.0.102
slon_start --config=../etc/slon_tools_sample.conf node3
(5)スレーブDBにレプリケーション構成作成(購読設定)
slaveDBの購読設定。set番号とnode番号を指定します。
これで、レプリケーションが開始されます。
- at 192.168.0.101
slonik_subscribe_set --config=../etc/slon_tools_sample.conf set1 node2 | slonik
- at 192.168.0.102
slonik_subscribe_set --config=../etc/slon_tools_sample.conf set1 node3 | slonik
生成されるスクリプト(set1 node2)
cluster name = replication_sample;
node 1 admin conninfo='host=192.168.0.100 dbname=testdb user=postgres port=5432';
node 2 admin conninfo='host=192.168.0.101 dbname=testdb user=postgres port=5432';
node 3 admin conninfo='host=192.168.0.102 dbname=testdb user=postgres port=5432';
try {
subscribe set (id = 1, provider = 1, receiver = 2, forward = yes);
}
on error {
exit 1;
}
echo 'Subscribed nodes to set 1';
(6)同期確認
- 同期状態確認
_replication_sample.sl_statusビューのsl_lag_time(遅延時間)が、レプリケーションの遅延時間の目安になります。
この時間が十数秒以下になれば、同期完了です。
psql sample;
sample=# select * from _replication_sample.sl_status;
st_origin | st_received | st_last_event | st_last_event_ts | st_last_received | st_last_received_ts | st_last_received_event_ts | st_lag_num_events | st_lag_time
-----------+-------------+---------------+----------------------------+------------------+----------------------------+----------------------------+-------------------+-----------------
1 | 3 | 31422929 | 2011-04-14 14:47:36.318008 | 31422921 | 2011-04-14 14:47:28.309014 | 2011-04-14 14:47:28.305486 | 8 | 00:00:08.317434
1 | 2 | 31422929 | 2011-04-14 14:47:36.318008 | 31422921 | 2011-04-14 14:47:28.835874 | 2011-04-14 14:47:28.305486 | 8 | 00:00:08.317434
(2 rows)
上記のテーブルも、pgadminツールを使うともっと簡単に確認できます。
- ログ確認
ログを監視。
ERRORが出たら失敗。レプリケーションスキーマを削除し、構築のやり直しを行ってください。
pg_dump(データをINSERTコマンドとしてダンプ)で半日くらいかかるデータでも、30分くらいでデータコピーまで完了します。
cd /var/log/slony/slony(set_id)/node(node_number)/ tail -f sample-YYYY-mm-DD_HH:SS:MM.log
運用メモ
- DBのメンテナンス
vacuum fullなどのメンテナンスは、ノード単位で実行する必要があります。(Postgresql9.0のS/Rは、マスタノードにvacuum fullをかけると、スレーブノードにまで適用されます。。。)
- vacuum full
vacuum fullを行うと、テーブル単位でロックしてしまうため、安全に行うには、slonプロセスをkillして行う必要があります。運用中にvacuum fullと同等の処理を行いたい場合は、pg_reorgを使用するとよいです。
- pg_reorg
http://reorg.projects.postgresql.org/index-ja.html
サービス運用中に実行可能なvacuum full代替。かなり便利です。
○できること
-
- オンライン CLUSTER (cluster index順に行を並び替える)
- ユーザの指定した順に行を並び替える
- オンライン VACUUM FULL (行の詰め合わせを行う)
○注意点
-
- スーパーユーザのみが実行することができます
- 対象のテーブルはPRIMARY KEYを持っている必要があります
動作内容は
(1)DBのコピーを作成
(2)コピーに対してレコードを再編成(並び替え)
(3)元のDBにリネーム
(4)差分を適用
といった感じです。
-
- インストール
パスの設定などがややこしいので、postgresqlのコンパイルディレクトリを利用してインストールします。
(postgresqlのコンパイルディレクトリのcontrib配下に展開すると、楽にインストールを行えます。)
cd /usr/local/src wget http://pgfoundry.org/frs/download.php/2845/pg_reorg-1.1.5.tar.gz tar xvfz pg_reorg-1.1.5.tar.gz -C /usr/local/src/postgresql-8.4.4/contrib/ cd /usr/local/src/postgresql-8.4.4/contrib/pg_reorg-1.1.5 make su - cd /usr/local/src/postgresql-8.4.4/contrib/pg_reorg-1.1.5 make install
pg_reorgの関数を登録
psql -f $PGSHARE/contrib/pg_reorg.sql DB名
- 実行例
# データベースhogeにオンライン CLUSTERを実行する pg_reorg -U user -d hoge # データベースfugaにオンライン VACUUM FULLを実行する pg_reorg -U user -d fuga -n
APPENDIX
slonik : slonyの設定情報を読み込ませる。
slonik_init_cluster : Clusterを作成する。Cluster単位でレプリケーションが行われる。 構成情報を標準出力にはき出す。
slonik_create_set : どのテーブルをレプリケーションするかの設定。1 Clusterに複数set持てる。構成情報を標準出力にはき出す。
slonik_subscribe_set : Slave側で、Masterをsubscribeする。Slaveの数だけこのコマンドを実行する。 構成情報を標準出力にはき出す。
slon_start (ノード番号) : slony start
slon_kill (ノード番号) : slony kill
slony_show_configuration : 設定情報表示
