今回triggerでpostgresqlのデータをmongodbへの同期方法についてまとめました。
登場人物
処理流れ
postgresqlの同期対象テーブルのレコードの変更があったら、triggerで検知して、 gearmanのclientがデータ変更情報をgearmanに送ります。
gearmanのworkerが変更データを拾って、加工(必要があれば)して、mongodbに反映します。
pggearmanについて
postgresqlの中に使われるgearman clientはGearman PostgreSQL Functionsです。
最後のリリースは2009年で、9.1以降のpostgresqlには動けません。
postgresql9.1以降にも使えるpggearmanを作ってgithubに上げました。
pggearmanのインストール
git clone https://github.com/wangyuehong/pggearman.git cd pggearman make && make install
postgresqlの設定ファイルに下記の設定を追加
pggearman.default_servers = 'localhost'
同期対象データベースに /usr/local/postgresql/share/contrib/pggearman.sql をロード
Trigger作成
- まず、triggerで呼ばれるUDFを作成
CREATE OR REPLACE FUNCTION send_to_gearman() RETURNS trigger AS $$ BEGIN PERFORM gman_do_background('replicate2mongo', CAST(row_to_json(NEW.*) AS text)); RETURN NULL; END; $$ LANGUAGE plpgsql;
- 次、同期対象テーブルにtriggerを定義
CREATE CONSTRAINT TRIGGER r2m_pgbench_accounts AFTER UPDATE or INSERT -- 例なので、DELETE未実装 ON pgbench_accounts DEFERRABLE INITIALLY DEFERRED -- transaction成功commitのみ実行させる FOR EACH ROW EXECUTE PROCEDURE send_to_gearman();
- 次、Gearmanのworkerを作成
my $worker = Gearman::Worker->new; $worker->job_servers('127.0.0.1:4730'); my $mongo_connection = MongoDB::Connection->new('host' => 'localhost:27017'); my $mongo_db = $mongo_connection->get_database('foo'); my $mongo_collection = $mongo_db->get_collection('pgbench_accounts'); $worker->register_function( replicate2mongo => sub { my ($job) = @_; my $json = decode_json($job->arg); ##ここで、いろんなデータ加工ができる $mongo_collection->update({ 'aid' => $json->{aid} }, { '$set' => $json }, { 'upsert' => 1 }); return 1; } ); $worker->work while 1;
pgbench_accountsのレコードの変更があったら、すぐmongodbのfoo.pgbench_accountsに反映されます。
パーフォーマンス検証
pgbenchでの検証結果
session数
|
trans per second
(triggerなし)
|
trans per second
(triggerあり)
|
avg trans time(triggerなし)
|
avg trans time(triggerあり)
|
1
|
1303.178338
|
1009.327054
|
0.763004
|
0.98487
|
4
|
2626.154359
|
1316.355209
|
1.51575
|
3.02863
|
8
|
2430.173718
|
1358.721837
|
3.27649
|
5.86531
|
まとめ
この案は簡単だけど、triggerの定義で結構パフォーマンス落ちるので、弊社製品には使われなかったが、他のとろこで使えるかもしれないので、まとめて書きました。