PostgreSQLでPub/Sub

PostgreSQL には Publish-Subscribe の仕組みがデフォルトで組み込まれている(NOTIFY/LISTEN)ことを教わったのでメモ

Publish-Subscribe Pattern

Publish-Subscribe パターン(以下 Pub/Sub)は メッセージの送信者が全受信者にイベントをブロードキャストする仕組み。
Publish-Subscribe Channel詳細は wikipedia “Enterprise Integration Patterns” のページを確認のこと。

PostgreSQL での Pub/Sub

Pub/Sub をするには、少なくとも次の3つの操作が必要。

  • メッセージをチャンネルに送信
  • チャンネルを購読する
  • チャンネルの購読をやめる

PostgreSQL では、上記操作をそれぞれ NOTIFY, LISTEN, UNLISTEN で行う。なお、コマンド NOTIFY のかわりに 関数 pg_notify を使うことも可能。

psql からの使い方

2つのチャンネル(foo と bar)を用意して、各チャンネルにメッセージを送信してみる。

subscriber
まずはチャンネルの購読から。LISTEN コマンドを使ってメッセージ受信。引数にはチャンネルを渡す。受け取れるのは LISTEN 状態になったあとのメッセージだけ。

$ psql dev
psql (9.1.6)
Type "help" for help.

dev=# LISTEN foo;
LISTEN
dev=# LISTEN foo;
LISTEN
dev=# LISTEN foo;
LISTEN
Asynchronous notification "foo" with payload "hello" received from server process with PID 2454.

bar チャンネルもあわせて購読
複数のメッセージがある場合、まとめて受け取る。

dev=# LISTEN bar;
LISTEN
dev=# LISTEN bar;
LISTEN
Asynchronous notification "bar" with payload "hello" received from server process with PID 2454.
Asynchronous notification "bar" with payload "world!" received from server process with PID 2454.

購読をやめるには UNLISTEN コマンドを利用。
foo チャンネルを UNLISTEN 後、  LISTEN を再開するまでの間に送信されたメッセージは受け取れない

dev=# UNLISTEN foo;
UNLISTEN
dev=# LISTEN foo;
LISTEN

publisher
チャンネル foo/bar にメッセージを送信する。
NOTIFY コマンドを使ってメッセージ送信。1つ目の引数がチャンネル、2つめの引数がメッセージ。

$ psql dev
psql (9.1.6)
Type "help" for help.

dev=# NOTIFY foo, 'hello';
NOTIFY
dev=# NOTIFY bar, 'hello';
NOTIFY
dev=# NOTIFY bar, 'world!';
NOTIFY

pg_notify 関数を使ってメッセージ送信。1つ目の引数がチャンネル、2つめの引数がメッセージ。

dev=# select pg_notify('foo', 'test message');
 pg_notify
-----------

(1 row)

送信元のプロセス ID は pg_backend_pid 関数で確認できる

dev=# SELECT pg_backend_pid();
 pg_backend_pid
----------------
           2454
(1 row)

上限サイズ

チャンネルは64バイト未満でなければいけない(NAMEDATALEN)。
超えた部分は削られる。

test=# NOTIFY a234567890123456789012345678901234567890123456789012345678901234567890, 'test';
NOTICE:  identifier "a234567890123456789012345678901234567890123456789012345678901234567890" will be truncated to "a23456789012345678901234567890123456789012345678901234567890123"
NOTIFY

メッセージは8000バイト未満でなければいけない(NOTIFY_PAYLOAD_MAX_LENGTH=BLCKSZ - NAMEDATALEN - 128. BLCKSZ=1024 * 8 = 8192 byte)
8000バイト以上の場合、エラーが発生する。

dev=# NOTIFY test, 'aaa...aaa'; -- >= 8000 bytes payload
ERROR:  payload string too long

プログラムからの使い方

publisher
トランザクション単位で NOTIFY 結果が subscriber に通知されるため、分離レベルを運用にあわせること。
サンプルプログラムでは AUTOCOMMIT を採用し、 NOTIFY のたびに通知されるようにしている。

subscriber
publisher から NOTIFY されたイベントは poll と同じ要領で処理できる。データベースコネクションに対して POLLIN イベントを捕まえればよい。

サンプルプログラム
NOTIFY と  LISTEN を使ってチャットっぽいことを実装したのが以下

応用例
Ruby で書かれたワーカーキュー queue_classic ではイベント通知の仕組みに PostgreSQL の LISTEN/NOTIFY を使っている。

Advertisements
Tagged with: , , ,
Posted in database, middleware
One comment on “PostgreSQLでPub/Sub

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Archives
%d bloggers like this: