Redis发布订阅模式-1

发布订阅模式

发布订阅模式可以说是耳熟能详了,它是属于设计模式中的行为模式,最大的好处就是起到解耦的作用,发布者不用关心在消息产生之后需要做什么,发布者只需要在通道里说“我发布了”,不用管有什么业务逻辑需要处理也不用管有多少的逻辑要处理,很简单明了。

我们平时用来解耦业务的消息队列就是实现了发布订阅模式,所以Redis可以在一些情况下做为消息队列来使用。

还是贴一张图把(网上盗的),解释下这种模式。

img


接下来看看在Redis中怎么实现

相关常用命令

PSUBSCRIBE pattern1 pattern2 //订阅一个或者多个符合给定模式的通道  ? ?* 和 * ?标识一个占位符,*标识多个占位符包括0个 ?*标识一个以上的占位符
PUBLISH channel1 message1   //发布消息到指定的通道
PUNSUBSCRIBE pattern1 pattern2 //退订一个或者多个符合给定模式的通道,不传pattern 代表退订所有
SUBSCRIBE channel1 channel2 //订阅一个或者多个通道 
UNSUBSCRIBE channel1 channel2 //退订一个或者多个通道 不传channel 代表退订所有

命令不复杂,我们来操作一下吧 首先发送一个命令到a_1的通道中,因为现在没有订阅者所以返回了0

1588153340852

我们新开一个客户端订阅这个通道,可以看到成功订阅了,返回了当前客户端订阅的通道数量,但是没有收到在订阅之前已经发送的消息,所以Redis的发布订阅的消息是没有持久化的,这是如果实现消息队列需要解决的问题

1588153502396

在第一个客户端发送几条消息

1588158591832

能看到第二个客户端接收到了消息

1588169010979


多说一点

  • Redis实例中的发布和订阅没有作用域的区分的,就算在不同的db间。比如你在db0中发布了一个消息,在db2中你同样能够收到,如果我们要区分不同的环境需要自己对channel命名来区分。
  • 这里需要注意的是,当一个客户端订阅成功一个通道之后,该客户端就不能执行除了订阅相关(SUBSCRIBE,UNSUBSCRIBE,PSUBSCRIBE,PUNSUBSCRIBE)的命令了,也就是相当于阻塞着一直等着消息。
  • 另外一点特别需要注意的是,我最开始的理解psubscribe只是支持模式匹配,最终的效果应该和subscribe是一样,也就是说当我执行psubscribe的时候,Redis实例会根据我写的模式去匹配channel,匹配上就订阅这个channel,比如"pubscribe a_*" 就应该订阅所有"a_"开头的channel,最后订阅的channel都是落到实际的channel上,比如"a_1,a_2"之类的channel。后来我有思考一个问题,当Redis实例中不存在a开头的channel,或者后面才有a开头的channel,我在最开始订阅 "a_"也是能接收到后面创建的channel中发送的信息
  • 其实Redis对于模式的订阅和普通的订阅是分开的,也就是同一个客户端订阅了模式a_,又订阅了a_1,那么你将会收到两条消息,就算你分别执行psubscribe a_1和subscribe a_1,这同样是订阅了两次,你会收到两次消息。
  • 我们可以做下测试,在上面的例子中我们已经通过subscribe a_1 订阅了a_1通道,并成功收到消息,我们再次执行psubscribe a_2 ,并在客户端1发送消息message5,可以看到我们收到两条相同的消息,具体原因会在下一节实现原理中。
  • 可以看见我把上面那句话给划掉了,是因为我在不同客户端测试的时候既然出现了不同的情况,具体原因不太清楚希望有人能解答下。

不同客户端执行相同命令产生不同的结果?

  1. 首先我用Another RDM的Console来进行订阅,命令会返回当前客户端订阅的通道数量,多次订阅不会重复订阅

    1588170587238

  2. 接着在客户端1中发送消息,命令会返回订阅的客户端数量

    1588170664563

  3. 接着在客户端2中进行模式订阅,可以看到订阅的通道数量变成2了,在客户端1发送消息,数量也变成2,所以我觉得发送信息的命令应该返回的是发送消息的数量

    1588170748596

    1588170814087

  4. 看到这里就已经证明我上面的说的话,但是因为Another没法监听的消息,我用redis-cli测试了一遍,然后就发现同样的命令既然产生不同的效果了。如下图,能看到当我psubscribe的时候没有输出东西,当我在客户端1发送消息的时候也只收到一条,而且客户端1显示消息数量也是3。而不是预想中的4。具体原因我也想不出来了。。希望大神解答。

    1588171030388

1588171114810

后来在官网看到了说法

Messages matching both a pattern and a channel subscription

A client may receive a single message multiple times if it's subscribed to multiple patterns matching a published message, or if it is subscribed to both patterns and channels matching the message. Like in the following example:

SUBSCRIBE foo
PSUBSCRIBE f*

In the above example, if a message is sent to channel foo, the client will receive two messages: one of type messageand one of type pmessage.

也就是印证了我最开始的想法。

posted @ 2020-05-07 16:59  RstarYan  阅读(805)  评论(0编辑  收藏  举报
$(function(){ $('#blogTitle h1').addClass('bounceInLeft animated'); $('#blogTitle h2').addClass('bounceInRight animated'); // 删除反对按钮 $('.buryit').remove(); initCommentData(); }); function initCommentData() { $('.feedbackItem').each(function() { var text = $(this).find('.feedbackListSubtitle .layer').text(); // 将楼层信息放到data里面 // $(this).find('.blog_comment_body').attr('data-louceng', text.replace(/^#/g, '')); if($(this).find('.feedbackListSubtitle .louzhu').length>0) $(this).addClass('myself'); var avatar = $(this).find('> .feedbackCon > span').html() || 'https://pic.cnblogs.com/face/sample_face.gif'; $(this).find('> .feedbackCon > .blog_comment_body').append('') }); } $(document).ajaxComplete(function(event, xhr, settings) { // 监听获取评论ajax事件 if(settings.url.indexOf('/mvc/blog/GetComments.aspx') >= 0) { initCommentData(); } });