聊聊 Redis 的高级特性之一: 发布订阅

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: Redis 发布订阅 (pub/sub) 是一种消息通信模式:发送者 (pub) 发送消息,订阅者 (sub) 接收消息。图中,消费者1和消费者2 订阅了 Redis 服务的频道 channel ,当生产者通过 PUBLISH 命令发送给频道 channel 时, 这个消息就会被发送给订阅它的两个客户端。

这篇文章,我们聊聊 Redis 的高级特性之一: 发布订阅

1 发布订阅

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

图中,消费者1和消费者2 订阅了 Redis 服务的频道 channel ,当生产者通过 PUBLISH 命令发送给频道 channel 时, 这个消息就会被发送给订阅它的两个客户端。

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

命令 用法 描述
PSUBSCRIBE PSUBSCRIBE pattern [pattern ...] 订阅一个或多个符合给定模式的频道
PUBSUB PUBSUB subcommand [argument [argument ...]] 查看订阅与发布系统状态
PUBLISH PUBLISH channel message 将信息发送到指定的频道
PUNSUBSCRIBE PUNSUBSCRIBE [pattern [pattern ...]] 退订所有给定模式的频道
SUBSCRIBE SUBSCRIBE channel [channel ...] 订阅给定的一个或多个频道的信息
UNSUBSCRIBE UNSUBSCRIBE [channel [channel ...]] 指退订给定的频道

2 客户端演示

我们开启两个 redis-cli 客户端,演示了发布订阅是如何工作的。

客户端 A 执行订阅命令:

subscribe mychannel

订阅命令执行成功后:

客户端 B 执行发布命令:

publish mychannel helloworld

发布命令执行成功后,客户端 A 就会接收到新的消息:

3 实现原理

每个 Redis 服务器进程都维持着一个表示服务器状态的 redis.h/redisServer 结构, 结构的 pubsub_channels 属性是一个字典, 这个字典就用于保存订阅频道的信息:

struct redisServer {
    // ...
    dict *pubsub_channels;
    // ...
};

其中,字典的键为正在被订阅的频道, 而字典的值则是一个链表, 链表中保存了所有订阅这个频道的客户端。

下图中, client2 、 client5 和 client1 就订阅了 channel1 , 而其他频道也分别被别的客户端所订阅:

当客户端调用 SUBSCRIBE 命令时, 程序就将客户端和要订阅的频道在 pubsub_channels 字典中关联起来。

举个例子,如果客户端 client10086 执行命令 SUBSCRIBE channel1 channel2 channel3 ,那么前面展示的 pubsub_channels 将变成下面这个样子:

当调用 PUBLISH channel message 命令, 程序首先根据 channel 定位到字典的键, 然后将信息发送给字典值链表中的所有客户端。

如果某个客户端执行命令 PUBLISH channel1 "hello moto" ,那么 client2 、 client5 和 client1 三个客户端都将接收到 "hello moto" 信息:

4 适用场景

在使用发布订阅功能时,需要理解两点。

1、保证先让消费者先订阅队列,然后再让生产者发布消息。

如果消费者异常挂掉并重新上线,它只能接收新的消息。在其下线期间,生产者发布的消息将无法被消费者接收,因为找不到该消费者,这些消息会被丢弃。

如果所有消费者都下线,那么生产者发布的消息将因为没有任何消费者而全部被丢弃。

2、发布订阅不具备数据持久化的能力

发布订阅相关的操作不会被写入到 Redis 数据库(RDB)或追加写入文件(AOF)中。如果 Redis 宕机并重新启动,Pub/Sub 的数据将会全部丢失。

基于上面的分析,发布订阅功能特别适合对少量消息丢失不敏感通知类型的场景。

5 实战演示

笔者开源了一个短信服务,为了提升系统性能,应用信息存储在本地内存中,定时任务会每隔30秒重新刷新一次缓存。

但在分布式部署的场景下,不同应用间的本地内存数据可能因为执行时间差异导致数据不同步。

基于这样的场景,我们可以使用 Redis 的发布订阅功能,实现本地内存的及时刷新。

1、配置 Redis 频道监听器容器

2、触发发布消息

当应用发送变化时,比如新增、修改、删除,则调用发送消息到频道方法。

下图,当我们启动两个短信平台应用,在控制台修改应用信息时,我们发现两个应用的本地内存都发生变化了。

6 总结

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

​ 消费者1和消费者2 订阅了 Redis 服务的频道 channel ,当生产者通过 PUBLISH 命令发送给频道 channel 时, 这个消息就会被发送给订阅它的两个客户端。

  1. 在使用发布订阅功能时,需要理解两点。

    • 保证先让消费者先订阅队列,然后再让生产者发布消息。

    • 发布订阅不具备数据持久化的能力。

  2. 发布订阅功能特别适合对少量消息丢失不敏感通知类型的场景。

  3. 笔者开源的短信平台项目,使用了 Redis 的发布订阅功能实现本地内存的实时同步。

短信平台地址https://github.com/makemyownlife/platform-sms


参考资料:

https://redisbook.readthedocs.io/en/latest/feature/pubsub.html

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
3月前
|
消息中间件 移动开发 NoSQL
Redis 协议 事务 发布订阅 异步连接
Redis 协议 事务 发布订阅 异步连接
|
3月前
|
NoSQL Redis
Redis之发布订阅
Redis之发布订阅
|
4月前
|
存储 NoSQL Redis
Redis 简介 + Python 操作发布订阅
Redis 简介 + Python 操作发布订阅
|
18天前
|
消息中间件 设计模式 缓存
Redis发布订阅:美丽的陷阱与不宜之境
Redis发布订阅:美丽的陷阱与不宜之境
48 1
|
3月前
|
消息中间件 NoSQL Java
硬核 | Redis Pub/Sub 发布订阅与宅男有什么关系?
硬核 | Redis Pub/Sub 发布订阅与宅男有什么关系?
51 0
|
3月前
|
存储 NoSQL 关系型数据库
Redis协议与异步方式(redis网络层、pipeline、事务、lua脚本、ACID特性、发布订阅、hiredis实现同步连接与异步连接)
Redis协议与异步方式(redis网络层、pipeline、事务、lua脚本、ACID特性、发布订阅、hiredis实现同步连接与异步连接)
74 0
|
3月前
|
NoSQL 网络协议 安全
Redis的高级特性与应用场景(二)
Redis的高级特性与应用场景(二)
23 0
|
3月前
|
存储 缓存 分布式计算
Redis的高级特性与应用场景(一)
Redis的高级特性与应用场景(一)
34 0
|
3月前
|
消息中间件 NoSQL Redis
Redis发布订阅
【1月更文挑战第7天】 消息队列 Redis 发布订阅(publsub)是一种消息通信模式︰发送者(pub)发送消息,订阅者(sub)接收消息。微信、微博、关注系统! Redis客户端可以订阅任意数量的频道。
171 1
|
4月前
|
存储 缓存 NoSQL
Redis数据库 | 发布订阅、主从复制、哨兵模式、缓存雪崩
Redis数据库 | 发布订阅、主从复制、哨兵模式、缓存雪崩
51 0