Redis打造低配版消息队列

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: Redis真的不愧是万金油,小到静态缓存,大到锁机制,消息队列,啥都能做。今天小马就来一起体验下redis实现消息队列的刺激感。

什么是消息队列

一听到消息队列,第一时间反应的当然是异步(请求链路长响应慢,则分开,并且有些动作可化同步为异步返回 ),限流,削峰(比如大量秒杀请求过来,先入队,后端自行按自己的节奏消费处理),解耦(比如上游订单服务处理完入队,下游有需要的自行订阅这个队列去处理)。本来想搞得正式一点的,查了下百科,一堆说明看得头晕,而且并不是很直观易懂。还是沿用一贯喜欢的招式,通俗一点讲吧。“消息队列”是在消息的传输过程中保存消息的容器。这句话真的非常精辟,可谓高度概括了这个词语的精髓。也就是说它其实是一个容器,至于容器是队列还是啥类型,它是不管的,能装就行。于是,我们来围观一下消息队列的两种模式或者说是消息通信模式:点对点模式和发布订阅模式。

点对点模式有的时候我们也叫做生产者消费者模式。生产者发送一条消息到queue,只有一个消费者能收到。也就是我们所说的1对1模式。
image.png

发布订阅模式我们有的时候也叫做广播。因为发布者发送到topic(主题有时也叫做频道channel,不同MQ取名不一样而已)的消息,只有订阅了topic的订阅者才会收到消息。也就是我们所说的1对多模式。
image.png

Redis实现原理

redis是如何实现上面两种模式的呢?还记得redis有一个数据类型叫List吗,我们通常直接称它为队列。因为它就是满足数据结构中队列的实现。于是,我们就用它来当容器实现消息队列。

实现点对点模式

我们在生产者客户端使用LPUSH命令将值依次插入某个KEY的列表当中,在消费者客户端使用LPOP命令移出并获取列表的第一个元素。这样就实现了一个简单的消息队列(请参照上面的说明图)。有人要问了,那我消费者如果去触发消费呢?嗯,是个好问题。简单的我们可以在消费者客户端直接使用while (true){consumerMessage();}这样子来轮询消费就可以了。

细心的你看肯定发现了,那这不是死循环吗?消费者不停地调用LPOP去查看List中是否有待处理消息,而这每一次都会发现一次连接,造成不必要的资源浪费。小机灵鬼的同学灵机一动,我可以采用休眠获取或者使用定时器隔段时间去获取呢。没错,这的确是个不错的方法,但是这个是存在问题的。

1.如果生产者速度大于消费者消费速度,消息队列长度会一直增大,时间久了会占用大量内存空间;

2.如果间隔时间过长,这样不能处理一些时效性的消息,睡眠时间过短,同样会在连接上造成比较大的资源开销。

那么有没有办法在生产者有数据的时候,我消费者就立马消费,如果没有数据则消费者一直等待,等到有数据了再立马消费呢?答应自然是肯定的。

我们来看Redis的阻塞获取列表系列的命令。先来看BLPOP命令,该命令移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。命令格式如:BLPOP key1 [key2 ] timeout 。啥意思呢,就是现在我要获取一个或多个队列中的一个数据出来,如果没有我就一直阻塞,直到超时就返回nil。

所以,我们消费者使用BLPOP命令就可以在LIST没有数据的时候直接阻塞,大大减少不断连接的开销。有的同学说,我还是不过瘾,这里非要设置一个超时时间,因为不设置就会报错,但是我阻塞超时完如果LIST还是没有数据我还是得连接。别急,你把阻塞时间设置为0试试,是不是就是一直阻塞啦。于是就算“死循环”也不会怕了。

下面我们就用例子来大概体验一下吧。
image.png

生产者


image.png

消费者


我们注意到消费者客户端BLPOP runoobkey 0这个命令,获取test3值之前是在一直等待生产者加入数据,当生产者一旦写入数据,立马就获取到值,下面显示了等待时间是262.35s。

实现发布订阅模式

点对点模式讲完了,来聊聊发布订阅模式。教程如是说:Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。Redis 客户端可以订阅任意数量的频道。注意这里的频道概念,有些MQ也称为主题,但意思差不多。

可以理解为,驾驶人员(客户端)先都订阅了交通广播电台(频道),然后其中有一个客户端(电台DJ)向频道发送了一个消息(发布交通管制信息),所有驾驶人员都收听到了这条消息。哈哈,是不是很好理解。
image.png

那Redis的命令是怎么实现的呢?教程里的这块例子非常清晰了,笔者就直接借用了。
image.png

啊,大功告成。你认为这样就完了吗?不,还是太年轻了。

Redis消息队列有什么弊端

相比于市场上的主流MQ,Redis消息队列似乎被用得比较少,其实是有原因的,我们还是用通俗的语言聊一下缺陷。

点对点模式:

1.做消费确认ACK比较麻烦,就是不能保证消费者在读取之后,未处理后的宕机问题。导致消息意外丢失。通常需要自己维护一个Pending列表,保证消息的处理确认。也就是取出之后没有应答处理完毕了没,就当作消费成功了。没有可靠性。

2.不能重复消费,一旦消费就会被删除。这一点仁者见仁吧。

3.不支持分组消费,需要自己在业务逻辑层解决。

发布订阅模式:

1.消息一旦发布,不接收消息就没了。换句话就是发布时若客户端不在线,则消息丢失,不能寻回。也就是发布出去就不管对方有没接收到了,因为没有接收应答。

2.不能保证每个消费者接收的时间是一致的。这点仁者见仁吧。

3.若消费者客户端出现消息积压,到一定程度,会被强制断开,导致消息意外丢失。通常发生在消息的生产远大于消费速度时。似乎这个缺陷比较严重,可靠性大打折扣。

所以对可靠性要求不高的话可以考虑Redis简单搞搞,但一般现在都上主流MQ了,毕竟能用上MQ的项目,体量和项目可靠性要求一般也不会低。元芳,你怎么看?

相关实践学习
基于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
相关文章
|
1月前
|
消息中间件 缓存 NoSQL
Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。
【10月更文挑战第4天】Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。随着数据增长,有时需要将 Redis 数据导出以进行分析、备份或迁移。本文详细介绍几种导出方法:1)使用 Redis 命令与重定向;2)利用 Redis 的 RDB 和 AOF 持久化功能;3)借助第三方工具如 `redis-dump`。每种方法均附有示例代码,帮助你轻松完成数据导出任务。无论数据量大小,总有一款适合你。
74 6
|
4月前
|
消息中间件 存储 负载均衡
Redis使用ZSET实现消息队列使用总结二
Redis使用ZSET实现消息队列使用总结二
72 0
|
2月前
|
消息中间件 存储 NoSQL
剖析 Redis List 消息队列的三种消费线程模型
Redis 列表(List)是一种简单的字符串列表,它的底层实现是一个双向链表。 生产环境,很多公司都将 Redis 列表应用于轻量级消息队列 。这篇文章,我们聊聊如何使用 List 命令实现消息队列的功能以及剖析消费者线程模型 。
97 20
剖析 Redis List 消息队列的三种消费线程模型
|
1月前
|
消息中间件 分布式计算 NoSQL
大数据-41 Redis 类型集合(2) bitmap位操作 geohash空间计算 stream持久化消息队列 Z阶曲线 Base32编码
大数据-41 Redis 类型集合(2) bitmap位操作 geohash空间计算 stream持久化消息队列 Z阶曲线 Base32编码
27 2
|
1月前
|
消息中间件 存储 NoSQL
python 使用redis实现支持优先级的消息队列详细说明和代码
python 使用redis实现支持优先级的消息队列详细说明和代码
37 0
|
3月前
|
消息中间件 NoSQL Redis
Redis Stream消息队列之基本语法与使用方式
这篇文章详细介绍了Redis Stream消息队列的基本语法和使用方式,包括消息的添加、读取、删除、修剪以及消费者组的使用和管理,强调了其在消息持久化和主备复制方面的优势。
69 0
|
4月前
|
消息中间件 存储 NoSQL
Redis使用ZSET实现消息队列使用总结一
Redis使用ZSET实现消息队列使用总结一
120 0
|
4月前
|
消息中间件 C语言 RocketMQ
消息队列 MQ操作报错合集之出现"Connection reset by peer"的错误,该如何处理
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
|
4月前
|
消息中间件 Java C语言
消息队列 MQ使用问题之在使用C++客户端和GBase的ESQL进行编译时出现core dump,该怎么办
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
|
18天前
|
消息中间件 存储 Kafka
MQ 消息队列核心原理,12 条最全面总结!
本文总结了消息队列的12个核心原理,涵盖消息顺序性、ACK机制、持久化及高可用性等内容。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。