目录
一、概要
二、特点
三、发布及订阅功能
四、Redis发布订阅命令
五、php实现redis发布-订阅
1、消息发布端
2、消息订阅端
六、订阅发布使用场景
七、在订阅时遇到错误
八、模式匹配(正则匹配)订阅
一、概要
Redis发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
Redis 发布订阅(pub/sub)实现了消息系统,发送者(在redis术语中称为发布者)在接收者(订阅者)接收消息时发送消息。传送消息的链路称为信道。
在Redis中,客户端可以订阅任意数量的信道。
- 消息发布
- 消息订阅
二、特点
发送者(发布者)不是计划发送消息给特定的接收者(订阅者)。而是发布的消息分到不同的频道,不需要知道什么样的订阅者订阅。
订阅者对一个或多个频道感兴趣,只需接收感兴趣的消息,不需要知道什么样的发布者发布的。
这种发布者和订阅者的解耦合可以带来更大的扩展性和更加动态的网络拓扑。
三、发布及订阅功能
1、 基于事件的系统中,Pub/Sub是目前广泛使用的通信模型,它采用事件作为基本的通信机制,提供大规模系统所要求的松散耦合的交互模式:订阅者(如客户端)以事件订阅的方式表达出它有兴趣接收的一个事件或一类事件;发布者(如服务器)可将订阅者感兴趣的事件随时通知相关订阅者。
2、 消息发布者,即publish客户端,无需独占链接,你可以在publish消息的同时,使用同一个redis-client链接进行其他操作(例如:INCR等)
3、 消息订阅者,即subscribe客户端,需要独占链接,即进行subscribe期间,redis-client无法穿插其他操作,此时client以阻塞的方式等待“publish端”的消息;这一点很好理解,因此subscribe端需要使用单独的链接,甚至需要在额外的线程中使用。
# 订阅一个redisChat频道redis 127.0.0.1:6379> SUBSCRIBE redisChat
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "redisChat"
3) (integer) 1#发布消息到redisChat频道,发布成功后,订阅者会收到信息
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 yiibai"
(integer) 1
1) "message"
2) "redisChat"
3) "Redis is a great caching technique"
1) "message"
2) "redisChat"
3) "Learn redis by yiibai"
四、Redis发布订阅命令
PUBLISH channel message #将信息发送到指定的频道。
SUBSCRIBE channel [channel …] #订阅给定的一个或多个频道的信息。
UNSUBSCRIBE [channel [channel …]] #退订给定的频道。PSUBSCRIBE pattern [pattern …] #订阅一个或多个符合给定模式的频道。根据模式来订阅,可以订阅许多频道
PUNSUBSCRIBE [pattern [pattern …]] #退订所有给定模式的频道。PUBSUB subcommand [argument [argument …]] #查看订阅与发布系统状态。
五、php实现redis发布-订阅
1、消息发布端
<?php//消息发布
$redis = new Redis();
// 第一个参数为redis服务器的ip,第二个为端口
$res = $redis->connect('121.41.88.209', 6379);
// test为发布的频道名称,hello,world为发布的消息
$res = $redis->publish('test','hello,world'.rand(00000,99999));
2、消息订阅端
<?php//消息订阅端
$redis = new Redis();
$res = $redis->pconnect('121.41.88.209', 6379);
$redis->setOption(\Redis::OPT_READ_TIMEOUT,-1);
$redis->subscribe(array('test'), 'callback');// 回调函数,这里写处理逻辑
function callback($instance, $channelName, $message) {echo $channelName, "==>", $message,PHP_EOL;
}
六、订阅发布使用场景
使用订阅频道达到解耦作用,场景:用户编辑某个模块需要清除缓存,可以在编辑模块后发布到频道,然后订阅该模块的清除缓存
七、在订阅时遇到错误
在命令执行redis订阅端脚本时,发现在终端会输出:
PHP Fatal error: Uncaught exception 'RedisException' with message 'read error on connection' in …
这个错误大概的意思就是遇到了一个未捕获的异常:RedisException,消息读取错误当连接的时候。 应该是redis的客户端读取超时原因导致。 很多人在github上留言能不能提供一个类似php的pconnect的接口,但是貌似redis官方对这个没有一个官方的解决办法。
错误解决办法(以下3种办法):
【1】设置,default_socket_time = -1 但是本机测试的时候,应该是版本不一样的原因,直接报错:
redis server went away
【2】给redis connect的时候( pconnect( host,port = 6379, $timeout = 0.0 ))给timeout设置一个较大的值。
【3】通过Redis自带的常量设置
$redis->setOption(Redis::OPT_READ_TIMEOUT, -1);
八、模式匹配(正则匹配)订阅
Redis 的Pub/Sub实现支持模式匹配。
客户端可以订阅全风格的模式以便接收所有来自能匹配到给定模式的频道的消息。
比如,将接收所有发到 test.name,test.phone,test.address...等等的消息,该这样写:
PSUBSCRIBE test.*
在终端回车后,同时再新的窗口里分别发布两个频道的消息,名字分别为:test.name和test.phone,然后切换到订阅端的窗口里,结果如下
127.0.0.1:6379> PUBLISH test.name hehe
(integer) 1
127.0.0.1:6379> PUBLISH test.name haha
(integer) 1
由上图可以看出,在订阅了test.*频道后,一共收到了 test.name和test.phone两个频道的消息,这就是模式匹配订阅。
3) "test.name"
4) "haha"
那么取消订阅匹配该模式的客户端也比较简单:
PUNSUBSCRIBE test.*
注意:不能在redis-cli中使用PUNSUBSCRIBE 取消退订,没有效果,指的是在php这些脚本中