相关链接

Redis 发布订阅 - 简单模式:https://kdocs.cn/l/sl5exWLEzq2x

Redis 发布订阅 - 复杂模式:https://kdocs.cn/l/sd0RbrsFajZE

生活化场景重现

学校时期,学级主任为了提高整个学级学生的写作能力,会要求我们订阅一些周刊例如《读者》《意林》。

简单模式:

同学各自订阅,然后出版商会把周刊递交给邮局【频道channel】,然后邮局会在递交给所订阅整个周刊的同学们【(订阅者/客户端)client】

复杂模式

出资班费后**班级【频道channel】订阅,然后这个周刊,班级内的同学【(订阅者/客户端)client】**都可以阅读

img

img

底层实现

服务器将所有的订阅关系都保存在服务器状态的pubsub_channels属性里面,在模式订阅里服务器也将所有模式的订阅关系都保存在服务器状态的pubsub_patterns属性里面。

struct redisServer {
    // ...
    // 保存所有模式订阅关系
    list *pubsub_patterns;
    // ...
}

pubsub_patterns 属性是一个链表,链表中的每个节点都包含着一个pubsubPattern结构,这个结构的pattern属性记录了被订阅的模式,而client属性则记录了订阅模式的客户端。

typedef struct pubsubPattern {
    // 订阅模式的客户端
    redisClient *client;
    // 被订阅的模式
    robj * pattern;
} pubsubPattern;

图片描述

每当客户端执行PSUBSCRIBE命令订阅某个或某些模式的时候,服务器会对每个被订阅的模式执行以下两个操作:

  1. 新建一个pubsubPattern结构,将结构的pattern属性设置为被订阅的模式(如:music.*),client 属性设置为订阅模式的客户端。
  2. pubsubPattern结构添加到pubsub_patterns链表的表尾。

实战演练 Gif动画

第一层窗口:发布订阅窗口

第二层窗口:1:订阅 it.new 频道、2:订阅 it.photo 频道

第三层窗口:1:订阅 it.* 模式频道、2: 订阅 it* 模式频道

img

应用场景

简单的应用场景的话, 以门户网站为例, 当编辑更新了某推荐板块的内容后:

CMS发布清除缓存的消息到channel (推送者推送消息)

门户网站的缓存系统通过channel收到清除缓存的消息 (订阅者收到消息),更新了推荐板块的缓存

Redis 发布订阅缺陷

作为我个人角度来看这个redis发布订阅,觉得挺鸡肋的,首先客户端必须得订阅,发布端才能发布信息,否则发布信息就报异常的错误。还有客户端一直要保持在线才能收到消息,和设计模式中的观察者模式极为相似。 所以总结一下,redis订阅模式有以下缺陷

1、redis系统的稳定性有关 对于旧版的redis来说,如果一个客户端订阅了某个或者某些频道,但是它读取消息的速度不够快,那么不断的积压的消息就会使得redis输出缓冲区的体积越来越大,这可能会导致redis的速度变慢,甚至直接崩溃。也可能会导致redis被操作系统强制杀死,甚至导致操作系统本身不可用。新版的redis不会出现这种问题,因为它会自动断开不符合client-output-buffer-limit pubsub配置选项要求的订阅客户端

2、数据传输的可靠性 任何网络系统在执行操作时都可能会遇到断网的情况。而断线产生的连接错误通常会使得网络连接两端中的一端进行重新连接。如果客户端在执行订阅操作的过程中断线,那么客户端将会丢失在断线期间的消息,这在很多业务场景下是不可忍受的。

所以如果我碰到类似的业务的话,我也不会选择redis的发布订阅模式,我会选择:rabbitMQ,rockedMQ,activitedMQ 等消息中间件

常用命令

下表列出了 redis 发布订阅常用命令:

序号 命令及描述
1 [PSUBSCRIBE pattern pattern …] 订阅一个或多个符合给定模式的频道。
2 [PUBSUB subcommand argument [argument …]] 查看订阅与发布系统状态。
3 PUBLISH channel message 将信息发送到指定的频道。
4 [PUNSUBSCRIBE pattern [pattern …]] 退订所有给定模式的频道。
5 [SUBSCRIBE channel channel …] 订阅给定的一个或多个频道的信息。
6 [UNSUBSCRIBE channel [channel …]] 指退订给定的频道。