Previous topic

制御コマンド

Next topic

ケーススタディ

This Page

パブリッシュ/サブスクライブ

SUBSCRIBE(channel_1, channel_2, ..., channel_N)
UNSUBSCRIBE(channel_1, channel_2, ..., channel_N)
UNSUBSCRIBE((unsubscribe, from, all, channels))
PSUBSCRIBE(pattern_1, pattern_2, ..., pattern_N)
PUNSUBSCRIBE(pattern_1, pattern_2, ..., pattern_N)
PUNSUBSCRIBE((unsubscribe, from, all, patterns))
PUBLISH(channel, message)

New in version 2.0.0.

計算時間: SUBSCRIBE はO(1)、 UNSUBSCRIBE はO(N)です。ここでNはすでにチャネルに接続しているクライアントの数です。 PUBLISH はO(N+M)です。Nはチャネルをsubscribeしているクライアントの数で、Mはすべてのクライアントによるsubscribeのパターン数です。 PSUBSCRIBE はO(N)です。NはすでにPSUBSCRIBEをしているクライアントのsubscribeのパターン数です。 PUNSUBSCRIBE はO(N+M)です。NはPUBSUBSCRIBEをしているクライアントがすでにsubscribeしているパターン数で、Mはクライアントからシステムにsubscribeされているパターン数の合計です。

SUBSCRIBEUNSUBSCRIBEPUBLISH はバブリッシュ/サブスクライブ・メッセージ・パラダイムです。sender(publisher)はメッセージを特定のreceiver(subscriber)に送信するのではなく、パブリッシュされたメッセージはチャネルに紐付けられます。このときどんなsubscriberがいるかは意識することはありません。subscriberは1つ以上のチャンネルを指定し、指定したチャンネルのメッセージのみ受信します。このpublisherとsubscriberのデカップリングはスケーラブルで動的なネットワークトポロジーを可能にします。

例えば、チャンネルfooとbarをsubscribeするためには、クライアントは SUBSCRIBE コマンドをチャンネル名とともに発行します。

SUBSCRIBE foo bar

他のクライアントによるすべてのメッセージはRedisサーバによりsubscribeされているすべてのクライアントにプッシュされます。形式は3要素のBulk replyになります。最初の要素はメッセージの型、2番目はチャンネル、3番目はメッセージの中身です。

1つ以上のチャンネルを購読しているクライアントは SUBSCRIBEUNSUBSCRIBE 以外のコマンドを発行するべきではありません。動的に他のチェンネルを subscribe や unsubscribe をすることは可能です。

SUBSCRIBEUNSUBSCRIBE の返信は先に説明したメッセージの形で送信されます。クライアントは最初の要素がメッセージの種類を示しているので、それに基づいて一貫したストリームを読み取ることができます。

プッシュされたメッセージのフォーマット

メッセージは3要素のMulti bulk replyです。最初の要素はメッセージの種類です。

  • “subscribe” : これは無事に2番目の要素にあるチャンネルをsubscribeできたことを示しています。3番目の要素は現在subscribeしているチャンネル数を示しています。
  • “unsubscribe” : これは2番目の要素にあるチャンネルを無事にunsubscribeできたことを示しています。3番目の要素は現在subscribeしているチャンネル数を示しています。もし0になっていたらひとつもチャンネルを購読していないことを示しています。クライアントはパブリック/サブスクライブの状態からは外れているのでどんなRedisコマンドも発行できます。
  • “message” : 他のクライアントによって発行された PUBLISH コマンドの結果のメッセージです。2番目の要素はチャンネル名、3番目の要素はメッセージの中身です。

一度にすべてのチャンネルをunsubscribeする

UNSUBSCRIBED コマンドが引数なしで呼び出された場合、現在subscribeしているすべてのチャンネルをunsubscribeしたことになります。unsubscribeしたすべてのチャンネルにその旨のメッセージが送られます。

ワイヤプロトコルの例

SUBSCRIBE first second
*3
$9
subscribe
$5
first
:1
*3
$9
subscribe
$6
second
:2

このとき他のクライアントからチャンネル “second” に対して PUBLISH を発行します。次は最初のクライアントが受け取るものです。

*3
$7
message
$6
second
$5
Hello

次にクライアントは UNSUBSCRIBE コマンドですべてのチャンネルからunsubscribeします。

UNSUBSCRIBE
*3
$11
unsubscribe
$6
second
:1
*3
$11
unsubscribe
$5
first
:0

PSUBSCRIBEとPUNSUBSCRIBE: パターンマッチによるsubscribe

Redisのパブリッシュ/サブスクライブの実装はパターンマッチもサポートしています。クライアントはglob形式のパターンを使って、パターンに該当するチャンネル名を持つ全てのメッセージを受信します。

たとえばコマンドはこんな感じです。

PSUBSCRIBE news.*

この場合は news.art.figurativenews.music.jazz などといったチャンネルのすべてのメッセージを受信します。すべてのglob形式のパターンが有効です。複数のワイルドカードが対応しています。

パターンマッチの結果受け取ったメッセージは異なったフォーマットで送信されます。:

  • メッセージタイプは “pmessage” です。他のクライアントによって PUBLISH されたメッセージの受信結果です。2番目の要素は該当したパターン、3番目の要素はチャンネル名で、最後の要素は実際のメッセージの中身です。

SUBSCRIBE, UNSUBSCRIBE, PSUBSCRIBE, PUNSUBSCRIBE コマンドと同様に、メッセージタイプが”psubscribe”や”punsubscribe”のメッセージを送信しているシステムによって認識されています。そのシステムが送信しているメッセージの形式は”subscribe”や”unsubscribe”のものと同様です。

パターンとチャンネル、両方のsubscribeに該当するメッセージ

1つのメッセージに対して複数のパターンが該当する、あるいはパターンとチャンネル名両方がメッセージに該当する場合、クライアントはあるメッセージを複数回受信します。たとえば次ような例があります:

SUBSCRIBE foo
PSUBSCRIBE f*

上の例ではもしメッセージがfooチャンネルに送信され場合、クライアントは2つのメッセージを受け取ります。それぞれのメッセージタイプは”message”と”pmessage”になります。

パターンマッチでsubscribe数を見る意味

“subscribe”, “unsubscribe”, “psubscribe”, “punsubscribe”のメッセージタイプでは、最後の要素は購読中のチャンネル数になっています。この数はクライアントがその時点でsubscribeしているチャンネルとパターンの合計です。クライアントは、すべてのチャンネルとパターンをunsubscribeした結果、この数が0になった時にだけパブリック/サブスクライブの状態を抜けることができます。

PUBLISHコマンドの詳細

PUBLISH コマンドはbulkコマンドです。最初の引数がターゲットクラスで2番目の引数が送信されるデータです。呼び出すとInteger replyが返ってきます。値はメッセージを受け取ったクライアント数です。(つまりこのクラスを監視しているクライアント数です)

プログラミング例

Pieter Noordhuisが素晴らしいサンプルとして、Event-machineとRedisを使って複数ユーザのハイパフォーマンスWebチャットを作りました。ソースコードももちろん公開されています。

クライアントライブラリの実装のためのヒント

受信したすべてのメッセージにはメッセージの配信のきっかけとなった元々のsubscriptionを持っているので(”message”であればチャンネル名、”pmessage”であればパターン)、クライアントライブラリは元々のsubscriptionとコールバックをハッシュ表を使ってひもづけることができます。(コールバック先は関数、ブロック、ポインタなどなんでもかまいません)

メッセージが受け取られたときには、メッセージを登録したコールバックに配信するために、O(1)の参照が行われます。