Redisのパブリッシュ・サブスクライブ(pub/sub)は、メッセージ送信者(publisher)がチャンネルにメッセージを送信し、そのチャンネルを購読している受信者(subscriber)がリアルタイムでメッセージを受け取る通信モデルです。クライアントは複数のチャンネルを同時に購読可能です。
例えば、チャンネル redisChat を購読するには以下のようにします:
redis 127.0.0.1:6379> SUBSCRIBE redisChat
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "redisChat"
3) (integer) 1
別のクライアントからこのチャンネルにメッセージを送信すると、購読中のクライアントに即座に配信されます:
redis 127.0.0.1:6379> PUBLISH redisChat "Redis is a great caching technique"
(integer) 1
redis 127.0.0.1:6379> PUBLISH redisChat "Learn redis by example"
(integer) 1
購読側の出力例:
1) "message"
2) "redisChat"
3) "Redis is a great caching technique"
1) "message"
2) "redisChat"
3) "Learn redis by example"
主なパブリッシュ・サブスクライブコマンド
| コマンド | 説明 |
|---|---|
PSUBSCRIBE pattern [...] | パターンにマッチする複数のチャンネルを購読 |
PUBSUB subcommand [...] | パブリッシュ/サブスクライブシステムの状態を確認 |
PUBLISH channel message | 指定チャンネルにメッセージを送信 |
PUNSUBSCRIBE [pattern [...]] | パターンベースの購読を解除 |
SUBSCRIBE channel [...] | 1つ以上のチャンネルを購読 |
UNSUBSCRIBE [channel [...]] | 指定チャンネルの購読を解除 |
Redis pub/sub と ActiveMQ の比較
- ActiveMQ は AMQP、MQTT、Stomp などのプロトコルおよび JMS 仕様をサポートするが、Redis はこれらの標準プロトコルをサポートしない。
- ActiveMQ はメッセージの永続化を提供するが、Redis の pub/sub はメッセージを保持せず、購読者がいない場合や接続中にのみ配信され、それ以外は破棄される。
- ActiveMQ はトランザクションや再送機能によりメッセージの信頼性を保証するが、Redis にはそのような保証機構がない。
したがって、高度なメッセージング機能が必要ない場合は、既存の Redis インフラ上でシンプルな pub/sub を利用する方が効率的である。
リストを使ったタスクキューの実装
Redis のリスト型(双方向リンクリストで実装)を利用して、シンプルなタスクキューを構築できる。プロデューサーは LPUSH でキューにタスクを追加し、コンシューマーは RPOP(または LPOP)でタスクを取り出す。
127.0.0.1:6379> LPUSH job_queue "process_order_123"
(integer) 1
127.0.0.1:6379> LPOP job_queue
"process_order_123"
空のキューに対してポーリングを避けるため、BLPOP を使用してブロッキング待ちが可能:
127.0.0.1:6379> BLPOP job_queue 0
# → キューに要素が追加されるまでブロック
# 別セッションで:
127.0.0.1:6379> LPUSH job_queue "urgent_task"
(integer) 1
# 元のセッションが即座に返す:
1) "job_queue"
2) "urgent_task"
優先度付きキューの実現
BLPOP(または BRPOP)は複数のキーを引数に取ることができ、いずれかのリストに要素がある場合、左から最初に見つかったリストから要素を取得する。この特性を利用して、優先度の高いキューを左側に配置することで、優先度付き処理を実現できる。
127.0.0.1:6379> LPUSH high_priority "critical_alert"
(integer) 1
127.0.0.1:6379> LPUSH normal_queue "routine_job"
(integer) 1
127.0.0.1:6379> BRPOP high_priority normal_queue 0
1) "high_priority"
2) "critical_alert"
127.0.0.1:6379> BRPOP high_priority normal_queue 0
1) "normal_queue"
2) "routine_job"