Redis发布订阅

Redis发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。

Redis客户端可以订阅任意数量的频道,下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系:

Redis发布订阅

当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:

Redis发布订阅

一个Redis client发布消息,其他多个redis client订阅消息,发布的消息“即发即失”,Redis不会持久保存发布的消息,消息订阅者也将只能得到订阅之后的消息,通道中此前的消息将无从获得。

消息发布者,无需独占链接,你可以在publish消息的同时,使用同一个redis-client链接进行其他操作。

消息订阅者,需要独占链接,即进行subscribe期间,redis-client无法穿插其他操作,此时client以阻塞的方式等待“publish端”的消息;因此这里subscribe端需要使用单独的链接,甚至需要在额外的线程中使用。

TCP默认连接时间固定,如果在这时间内sub端没有接收到pub端消息,或pub端没有消息产生,sub端的连接都会被强制回收。

PHP实践

发布者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php

// Redis发布订阅-发布者

require '../common.php';

$redis = new Redis();

$redis->connect('127.0.0.1',6379);

$i = 0;
while($i < 1000) {
print_log('send msg: '.'msg ' .$i);
$redis->publish('msg','msg ' .$i);
$i++;
sleep(1);
}

$redis->close();

订阅者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php

// Redis发布订阅-订阅者

require '../common.php';

$redis = new Redis();

$redis->connect('127.0.0.1',6379);


$redis->subscribe(['msg'], 'callback');

function callback($instance,$channelName,$message)
{
print_log('收到频道[ '.$channelName.' ]的消息:'.$message);
}

## 输出
21:53:05 收到频道[ msg ]的消息:msg 248
21:53:06 收到频道[ msg ]的消息:msg 249
21:53:07 收到频道[ msg ]的消息:msg 250
21:53:08 收到频道[ msg ]的消息:msg 251
...

应用场景

Redis利用发布订阅可以作为简单的消息队列来用,但是和专业的MQ中间件(RabbitMQ\Kafka)比较的话,没有持久化(可以用list替代)和ACK确认机制,适合于消息投递率要求不高的场景,例如:

  • 短信发送、日志发送等功能解耦场景;
  • 构建实时消息系统,比如普通的即时聊天,群聊等功能;

参考文档

有用就打赏一下作者吧!