Redis

洞悉Redis技术内幕:缓存,数据结构,并发,集群与算法
帅旋
关注
充电
IT宅站长,技术博主,共享单车手,全网id:arthinking。

Redis中的发布订阅机制

发布于 2021-06-16 | 更新于 2024-02-26

Redis的发布订阅功能有以下命令组成:

  • SUBSCRIBE channel [channel ...]

    • 订阅给定的一个或多个频道的信息;

    • SUBSCRIBE channel

  • UNSUBSCRIBE [channel [channel ...]]

    • 退订给定的频道

    • UNSUBSCRIBE channel

  • PUBLISH channel message

    • 用于将信息发送到指定的频道;

    • PUBLISH channel itzhai.com

  • PUBSUB subcommand [argument [argument ...\]]

    • 查看订阅与发布系统状态

    • PUBSUB CHANNELS

  • PSUBSCRIBE pattern [pattern ...]

    • 订阅一个或多个符合给定模式的频道

    • PSUBSCRIBE site.*

  • PUNSUBSCRIBE [pattern [pattern ...\]]

    • 退订给定模式的频道

    • UNSUBSCRIBE site.*

如下,通过给定的模式频道进行订阅和发布消息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 客户端A订阅模式频道
127.0.0.1:6379> PSUBSCRIBE site.*
psubscribe
site.*
1

# 客户端B向模式频道发布消息
127.0.0.1:6379> PUBLISH site.itzhai "hello world!!!"
1

# 客户端A输出
pmessage
site.*
site.itzhai
hello world!!!

Redis在服务端通过链表的形式维护了每个频道的客户端的订阅记录,每次发布消息的时候,都从链表中找到所有相关的客户端的socket连接,并发送订阅消息给各个客户端。Redis中存放客户端订阅关系的相关数据结构:

1
2
3
4
5
6
struct redisServer {
// ...
dict *pubsub_channels; // 保存所有频道订阅关系
list *pubsub_patterns; // 保存所有模式订阅关系
// ...
};

具体结构如下图所示:

image-20211010133322675

在dict字典中,每个键值对存储一个频道的订阅关系,key为频道名称,value为链表结构,存储该频道所有订阅的客户端。

每当执行SUBSCRIBE命令的时候,执行把客户端追加到字典中对应频道的key的values链表中即可。

每当执行PUBLISH命令的时候,从字典中找到对应的频道键值对,依次遍历values中所有的客户端进行发送消息即可。

在list链表中,保存了所有的模式频道订阅关系。

每当执行PUBLISH命令的时候,除了在pubsub_channels寻找频道订阅关系,发给具体的频道的所有客户端之外,同时,Redis会遍历pubsub_patterns中的所有订阅模式频道,找到与当前发布消息频道匹配的模式频道,将消息发送给该模式频道的客户端。

1、发布订阅的优缺点

通过使用Redis的发布订阅机制,很容易实现消息的订阅与通知,可以快速实现一个消息队列。

但是,该消息队列的缺点也比较明显,请大家慎用:

  • 发布的消息不支持持久化,如果Redis挂了,那么发布的消息也就丢失了;或者消息发送给了一半的订阅者,Redis就挂了,那么剩下的一般订阅者也就不会收到消息了;或者准备发送消息给其中一个订阅者的时候,该订阅者失去连接了,消息也会丢失;
  • 消息发送缺少ACK机制,不能保证消息一定会被消费…

针对可靠性要求低的业务,为了简单快速实现,可以使用Redis的发布订阅机制来实现消息通知。而对于可靠性要求比较高的,则可以尝试Redis 5.0的新数据结构Stream,具体用法和原理,参考Part I部分相关内容。

本文作者: 帅旋

本文链接: https://www.itzhai.com/columns/redis/pub-sub.html

版权声明: 版权归作者所有,未经许可不得转载,侵权必究!联系作者请加公众号。

×
IT宅

关注公众号及时获取网站内容更新。