Redis发布/订阅
一、说明:
订阅,取消订阅和发布实现了发布/订阅消息范式(引自wikipedia),发送者(发布者)不是计划发送消息给特定的接收者(订阅者)。而是发布的消息分到不同的频道,不需要知道什么样的订阅者订阅。订阅者对一个或多个频道感兴趣,只需接收感兴趣的消息,不需要知道什么样的发布者发布的。这种发布者和订阅者的解耦合可以带来更大的扩展性和更加动态的网络拓扑。
二、发布及订阅功能:
- 基于事件的系统中,Pub/Sub是目前广泛使用的通信模型,它采用事件作为基本的通信机制,提供大规模系统所要求的松散耦合的交互模式:订阅者(如客户端)以事件订阅的方式表达出它有兴趣接收的一个事件或一类事件;发布者(如服务器)可将订阅者感兴趣的事件随时通知相关订阅者。
- 消息发布者,即publish客户端,无需独占链接,你可以在publish消息的同时,使用同一个redis-client链接进行其他操作(例如:INCR等)
- 消息订阅者,即subscribe客户端,需要独占链接,即进行subscribe期间,redis-client无法穿插其他操作,此时client以阻塞的方式等待“publish端”的消息;这一点很好理解,因此subscribe端需要使用单独的链接,甚至需要在额外的线程中使用。
三、PUBLISH端代码:
<?php /** * redis sub(消息订阅端) * @date 2016-09-20 15:00 */ $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));
说明:发布一个名字叫test的频道,信息是:hello,world
四、SUBSCRIBE端代码:
<?php /** * redis sub(消息订阅端) * @date 2016-09-20 15:00 */ $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; }
//ThinkPHP 使用
public function publish() { $redis = RedisInstance::getInstance(); $redis->publish('test','ThinkPHP browser output:'.date('Y-m-d H:i:s',time())); }
说明:已经订阅到了刚才发布的 'ThinkPHP browser output'消息:
五、遇到的错误代码:
在命令执行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,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...等等的消息,该这样写:
PUBSCRIBE test.*
说明:在终端回车后,同时再新的窗口里分别发布两个频道的消息,名字分别为:test.name和test.phone,然后切换到订阅端的窗口里,结果如下图所示:
由上图可以看出,在订阅了test.*频道后,一共收到了 test.name和test.phone两个频道的消息,这就是模式匹配订阅。
那么取消订阅匹配该模式的客户端也比较简单:
PUNSUBSCRIBE test.*