一、引入(是什么?)

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

  各位都是务实的人,所以我就不长篇大论讲他的概念了,举个类似的例子来说明就好。

  大家肯定都有用微信,我们平时关注了订阅号,每次他发布消息的时候,我们就能看到。这就是一个消息订阅/发布的场景。

  在Redis中,你可以设定对某一个key值进行消息发布及消息订阅,当一个key值上进行了消息发布后,所有订阅它的客户端都会收到相应的消息。

 

redis订阅和发布 消息推送    tn redis消息订阅与发布 场景_发布订阅

二、redis订阅/发布功能使用场景(为什么用?)

  这一功能最明显的用法就是用作实时消息系统,比如普通的即时聊天,群聊,实时提醒等功能。

  我在项目中用到的场景:神奇电波落地页接口需要提供购买人和购买人数

三、实例:订阅/发布命令(怎么用?)

     

1.SUBSCRIBE 订阅给定的一个或多个频道的信息。

2.PUBLISH 将信息发送到指定的频道。

3.PUBSUB 查看订阅与发布系统状态

 例:PUBSUB CHANNELS test*

4.PSUBSCRIBE 订阅一个或多个符合给定模式的频道。

 

5.UNSUBSCRIBE[channel [channel ...]] 指退订给定的频道。

6.PUNSUBSCRIBE[pattern [pattern ...]] 退订所有给定模式的频道。

官方教程:http://www.redis.net.cn/tutorial/3514.html

 

 

四、php实现redis订阅发布

SUBSCRIBE端代码:

<?php
/**
 * redis sub(消息订阅端)
 */

$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;
}

PUBLISH端代码:

<?php
/**
 * redis sub(消息发布端)
 */
$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));

SUBSCRIBE端代码(redis集群):

$RedisNode = array('192.168.0.224:7000', '192.168.0.224:7001', '192.168.0.224:7002', '192.168.0.224:7003', '192.168.0.224:7004', '192.168.0.224:7005', 1.5, 1.5);
$redis = getRedis();
$redis->setOption(Redis::OPT_READ_TIMEOUT, -1);
$redis->subscribe(array('testChannel'), 'callback');

// 回调函数,这里写处理逻辑
function callback($instance, $channelName, $message)
{
 echo $channelName, "==>", $message,PHP_EOL;
}


function getRedis($redisConfig=array())
{
    global $RedisNode, $RedisPassWord;
    try {
        if(!empty($redisConfig)){
            $redis = new Redis();
            $redis->connect($redisConfig['host'],$redisConfig['port']);
            $redis->auth($redisConfig['pwd']);
            return $redis;
        }
        $redis = new RedisClusterClass(null,$RedisNode);
        return $redis;
    } catch (Exception $e) {
        exit;
    }
}

 

五、注意事项

1.在命令执行redis订阅端脚本时,发现在终端会输出:

PHP Fatal error:  Uncaught exception 'RedisException' with message 'read error on connection' in …

       这个错误大概的意思就是遇到了一个未捕获的异常:RedisException,返回的错误信息是读取连接错误。 应该是redis的客户端读取超时原因导致。 

(最新测试,在我的服务器上发现,只要1分钟没有接收到消息就会报错)

错误解决办法:

通过Redis自带的常量设置

$redis->setOption(Redis::OPT_READ_TIMEOUT, -1);

2.连接redis集群时,1分钟退出

错误解决办法:

设置,default_socket_time = -1 :

ini_set('default_socket_timeout', '-1');

 3.消费要快!

    Redis有输出缓冲区限制,发布的消息要及时消费,否则sub客户端会被强制关闭,查看redis的日志可以看到这句报错:

subscribe scheduled to be closed ASAP for overcoming of output buffer limits.

 六、与其他消息系统对比

1.Redis发布订阅与Kafka
(1)redis 消息推送(基于分布式 pub/sub)多用于实时性较高的消息推送,Kafka有一些延迟

(2)Redis无法对消息持久化存储,一旦消息被发送,如果没有订阅者接收,那么消息就会丢失。Kafka中消息被消费后不会被删除,而是到配置的expire时间后,才删除

(3)kafka中多个订阅者可以分组,发布一个消息后,同一个组里只有一个订阅者会收到该消息,这样可以用作负载均衡。例:有100台服务器每台服务器都是一个订阅者,都订阅了这个 topic,但是他们可能分为三组,A组50台,用来真的做发布文章,B组20台,用来写log,C组30台,用来存档备份……

            

redis订阅和发布 消息推送    tn redis消息订阅与发布 场景_Redis_02

 

 

2.Redis发布订阅与ActiveMQ的比较

(1)ActiveMQ支持多种消息协议,包括AMQP,MQTT,Stomp等,并且支持JMS规范,但Redis没有提供对这些协议的支持;
(2)ActiveMQ提供持久化功能,但Redis无法对消息持久化存储,一旦消息被发送,如果没有订阅者接收,那么消息就会丢失;
(3)ActiveMQ提供了消息传输保障,当客户端连接超时或事务回滚等情况发生时,消息会被重新发送给客户端,Redis没有提供消息传输保障。
总之,ActiveMQ所提供的功能远比Redis发布订阅要复杂,毕竟Redis不是专门做发布订阅的,
但是如果系统中已经有了Redis,并且需要基本的发布订阅功能,就没有必要再安装ActiveMQ了,因为可能ActiveMQ提供的功能大部分都用不到,而Redis的发布订阅机制就能满足需求。