【中间件系列】浅析redis是否适合做消息队列

文章目录

    • 一、简单的list消息队列
        • 1.命令示例
        • 2.伪代码示例
        • 3.方案优劣
    • 二、Pub/Sub发布订阅
        • 1.消息丢失
        • 2.消息堆积
    • 三、相对成熟的Stream
        • 1.redis命令介绍
        • 2.多消费者组测试
        • 3.Stream会持久化吗?
        • 4.消息堆积如何解决?
    • 总结

  用redis也是比较久了,并且也对其他消息中间件也用了相当多的时间,现在就redis是否适合做消息队列来梳理下,获取梳理完之后,可以有一个更加清晰的认知。笔者会从以下几个方面进行梳理。

在这里插入图片描述

一、简单的list消息队列

  众所周知,redis常见的数据结构有StringHashListSetzset。其中List可以是一个列表结构。可以通过LPUSHRPOP两个命令来实现一个简单的队列。

  • LPUSH 将元素依次插入到列表头部
  • RPOP 获取最后一个元素,并且删除。

  如下图所示:生产者通过LPUSH命令,依次插入a、b、c、d四个元素。消费者通过RPOP命令进行消费。

image-20240602102434914

1.命令示例

生产者:

# 通过LPUSH命令往test_queue填充a、b、c、d
127.0.0.1:6379> LPUSH test_queue a
(integer) 1
127.0.0.1:6379> LPUSH test_queue b
(integer) 2
127.0.0.1:6379> LPUSH test_queue c
(integer) 3
127.0.0.1:6379> LPUSH test_queue d
(integer) 4
127.0.0.1:6379>

消费者:

消费者
127.0.0.1:6379> RPOP test_queue
"a"
127.0.0.1:6379> RPOP test_queue
"b"
127.0.0.1:6379> RPOP test_queue
"c"
127.0.0.1:6379> RPOP test_queue
"d"
127.0.0.1:6379> RPOP test_queue
(nil)
127.0.0.1:6379>
2.伪代码示例

  生产者相对简单,以简单的订单支付为例子

//在订单支付成功之后发送给积分系统
public void afterPayHandler(Order order){
	//发送消息到积分系统
	redisTemp.LPUSH("order",order);
}

消费者

public void orderMessageListener(){
	while(true){
		//获取订单信息
		Order order = redisTemp.RPOP("order");
        if(order != null){
            //做积分系统的业务,如添加积分等逻辑。
        }
	}
}

  如上所示:消费者在消费的时候,必须通过循环一直拉取队列数据,达到数据的实时性,但是也出现了CPU空转的问题。如果我们判断空的时候sleep休眠一段时间,那就会存在消息实时性问题。休眠多久合适就成为了难以处理的问题。

好在redis有阻塞拉取的命令。

BRPOP test_queue 10(秒)。拉取命令,阻塞10秒。如果是0就是一直阻塞。

3.方案优劣
  1. 优点:足够简单,也很好理解。但是我确实是想不到哪个场景适合这个方案(笑哭)。感觉也只能算普及知识了。
  2. 缺点
    1. 不支持多消费者。任何一个消费者将redis的元素拉取删除之后,其他消费者都无法再次拉取到。那就只能仅限于一对一消费了。
    2. 消息丢失。没有ACK机制,如果拉取消息后宕机后,无法正常消费,就会导致消息的丢失。

二、Pub/Sub发布订阅

  List数据结构可以认为是开发者为了简单方便,从而引进的一种消息队列的方式,但是绝不”正宗“。Pub/Sub这种从名字上可以看出来,就是专门为了消息队列而生的。

image-20240602203541185

  ​ 从上图可以看出,发布订阅模式,解决了多消费者的问题。但是还是存在两个问题。

1.消息丢失

  发布订阅模型,没有进行消息存储,只是一个单纯的通道,实时的把消息传送给消费者。那么这样就会有一个问题,如果消费者中间下线,再次上线的时候,只能从最新的位置进行消费,这样就会有消息丢失啦。

2.消息堆积

在这里插入图片描述

  上文说,发布订阅模型没有基于任何数据类似,因此,这个操作不会写入RDBAOF中(redis持久化机制)。另外,在消息堆积的时候,数据是通过Buffer缓冲区实现的。这个缓冲区的大小可以在redis中进行配置。如果超过了缓冲区配置的上限,此时,Redis 就会「强制」把这个消费者踢下线。

  总的说,这个发布订阅模式相对比较脆弱,虽然解决了多消费者的问题,但是消息一致性较低,消息丢失概率较高(发布版本时重启了就可能丢消息),试用的场景较少。

三、相对成熟的Stream

  Redis5.0 中增加了Stream消息队列相对成熟,解决了较多的问题。

  1. 支持消息ACK反馈,在消息消费成功的时候,返回消费成功,才不会再次推送消息。
  2. 支持多消费者组。
  3. 消息堆积问题优化。

在这里插入图片描述

1.redis命令介绍

发布命令

解释 
#topic为 myStream1 
# * 代表使用自动生成的ID作为消息的ID
# 接下来是多个 field value 组成的信息。
127.0.0.1:6379> XADD myStream1 * name zhangsan sex 20
"1717500637523-0"
127.0.0.1:6379> XADD myStream1 * name lisi sex 20
"1717500644429-0"
127.0.0.1:6379>

消费命令

# 消费myStream队列的10个数据,最后的0意思是从头开始消费。
127.0.0.1:6379> XREAD COUNT 10 STREAMS myStream1 0
1) 1) "myStream1"
   2) 1) 1) "1717500637523-0"
         2) 1) "name"
            2) "zhangsan"
            3) "sex"
            4) "20"
      2) 1) "1717500644429-0"
         2) 1) "name"
            2) "lisi"
            3) "sex"
            4) "20"
127.0.0.1:6379>
2.多消费者组测试
#创建一个消费者组为myGroup1并且指定消费位置。最后这个长串是信息的id
127.0.0.1:6379> XGROUP CREATE myStream1 myGroup1 1717500644429-0
OK
#消费者组消费,消费者组为myGroup1 当前消费者id为consumer1 拉取10个信息  注意最后这个 ‘>‘
127.0.0.1:6379> XREADGROUP GROUP myGroup1 consumer1 COUNT 10 STREAMS myStream1 >
1) 1) "myStream1"
   2) 1) 1) "1717501299234-0"
         2) 1) "name"
            2) "lisi"
            3) "sex"
            4) "20"
127.0.0.1:6379>

验证ACK机制

  1. myGroup1消费者组拉取一次之后将所有的消息拉取回来
  2. 因为没有进行消息反馈ACK。所以再次拉取的时候,还是将全量的消息拉取回来。
  3. 执行一次ACK命令之后,再次拉取消息,发现少了一条消息。
  4. 再次执行ACK命令后,拉取不到消息了。
127.0.0.1:6379> XREADGROUP GROUP myGroup1 consumer1 COUNT 10 STREAMS myStream1 0
1) 1) "myStream1"
   2) 1) 1) "1717501299234-0"
         2) 1) "name"
            2) "lisi"
            3) "sex"
            4) "20"
      2) 1) "1717502213457-0"
         2) 1) "name"
            2) "lisi"
            3) "sex"
            4) "20"
127.0.0.1:6379> XREADGROUP GROUP myGroup1 consumer1 COUNT 10 STREAMS myStream1 0
1) 1) "myStream1"
   2) 1) 1) "1717501299234-0"
         2) 1) "name"
            2) "lisi"
            3) "sex"
            4) "20"
      2) 1) "1717502213457-0"
         2) 1) "name"
            2) "lisi"
            3) "sex"
            4) "20"
127.0.0.1:6379>
127.0.0.1:6379>
127.0.0.1:6379>
127.0.0.1:6379> XACK myStream1 myGroup1 1717502213457-0
(integer) 1
127.0.0.1:6379> XREADGROUP GROUP myGroup1 consumer1 COUNT 10 STREAMS myStream1 0
1) 1) "myStream1"
   2) 1) 1) "1717501299234-0"
         2) 1) "name"
            2) "lisi"
            3) "sex"
            4) "20"
127.0.0.1:6379> XACK myStream1 myGroup1 1717501299234-0
(integer) 1
127.0.0.1:6379> XREADGROUP GROUP myGroup1 consumer1 COUNT 10 STREAMS myStream1 0
1) 1) "myStream1"
   2) (empty list or set)
127.0.0.1:6379>
3.Stream会持久化吗?

  会,不管是RDB 还是AOF都会写入。所以不用担心宕机的问题。

4.消息堆积如何解决?

  既然会将Stream会进行持久化,那么必然消息也会保存在内存中,但是为了内存爆炸,Stream可以在XADD命令的时候,可以通过MAXLEN命令指定消息的最大长度,在超过最大长度的时候,旧消息会被删除,只保留固定长度的新消息。这样看来,消息堆积的问题只是进行了优化,并没有完美的解决

总结

  到此,获取对于redis消息队列的历史有了一定的了解,redis作为运行在内存的数据库而言,这个功能已经是很不错了,或许你的场景足够简单,消息的数量不多,并且对于消息的丢失不是特别的敏感的话,redis的Stream消息队列也是一个不错的选择。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/689561.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AI数据分析:用deepseek根据Excel数据绘制分裂饼形图

工作任务:要绘制下面表格中月活用户占比的分裂饼形图 在deepseek中输入提示词: 你是一个Python编程专家,要完成一个Python脚本编写的任务,具体步骤如下: 读取Excel文件"F:\AI自媒体内容\AI行业数据分析\poetop5…

保姆级教程:以SAR图像目标检测为例

一、项目出发点 AI Studio为我们提供了免费的GPU资源,当我们在NoteBook环境中把代码调试成功后,通常一个训练任务耗时较长,而Notebook离线运行有时长限制,一不小心就容易被kill掉。 如何解决这一问题? 后台任务帮到…

探索智慧农业系统架构的设计与应用

随着科技的不断进步和农业现代化的推进,智慧农业正逐渐成为农业发展的重要趋势。智慧农业系统架构的设计与应用,将农业生产与信息技术相结合,为农业生产提供了新的思路和解决方案。本文将深入探讨智慧农业系统架构的设计与应用,从…

2021JSP普及组第二题:插入排序

2021JSP普及组第二题 题目: 思路: 题目要求排序后根据操作进行对应操作。 操作一需要显示某位置数据排序后的位置,所以需要定义结构体数组储存原数据的位置和数据本身排序后所得数据要根据原位置输出排序后的位置,所以建立一个新…

android中调用onnxruntime框架

创建空白项目 安装Android Studio及创建空白项目参考:【安卓Java原生开发学习记录】一、安卓开发环境的搭建与HelloWorld(详细图文解释)_安卓原生开发-CSDN博客 切记:build configuration language 一定选择Groovy!官…

mysql报错 Duplicate entry

在MySQL中,当你尝试执行插入(INSERT)或更新(UPDATE)操作时,如果目标表中存在唯一索引(包括主键索引、唯一约束索引等),并且你要插入或更新的数据在该索引列上的值与表中已…

电机控制系列模块解析(28)—— 其他功能概述

其他功能概述 软件侧:观测器估计发散保护、时序异常检测 主电路侧:IGBT结温估算、直流母线电容容值估算 电机侧:电机温度估计、轴承异常估计、电机退磁检测 负载侧:负载不平衡检测、掉载检测、负载惯量自适应 上述各项功能&a…

Diffusers代码学习: IP-Adapter Inpainting

IP-Adapter还可以通过Inpainting自动管道和蒙图方式生成目标图片。 # 以下代码为程序运行进行设置,使用Inpainting 的自动管道, import os os.environ["HF_ENDPOINT"] "https://hf-mirror.com"from diffusers import AutoPipelin…

【React】vscode 中 React 自动补齐标签设置

1.打开设置 2.搜索 includeLanguages 3. 在Emmet 下,点击“添加项”,添加一项 javascript --> javascriptreact 4. 重启vs code

学习笔记——路由网络基础——汇总静态路由

4、汇总静态路由 (1)定义 静态路由汇总:多条静态路由都使用相同的送出接口或下一跳 IP 地址。(将多条路由汇总成一条路由表示) (2)目的 1.减少路由条目数量,减小路由表,加快查表速度 2.增加网络稳定性 (3)路由黑洞以及路由环路的产生…

循环语句大揭秘:while、do-while、for、foreach你都掌握了吗?

哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一…

idm2024最新完美破解版免费下载 idm绿色直装版注册机免费分享 idm永久激活码工具

IDM 2024破解版重新开发了调度程序和MMS协议支持、重新设计和增强的下载引擎、与所有最新浏览器的独特高级集成、改进的工具栏以及大量其他改进和新功能,这一全新的更新,使得IDM下载器更加完美。值得一提的是,它可以借助油猴浏览器的脚本&…

GAN网络理论和实验(二)

文章目录 一、说明二、什么是生成对抗网络?三、判别模型与生成模型四、生成对抗网络的架构五、你的第一个 GAN六、准备训练数据七、实现鉴别器八、实现生成器九、训练模型十、检查 GAN 生成的样本十一、使用 GAN 生成手写数字十二、准备训练数据十三、实现鉴别器和生…

【机器学习】XGBoost: 强化学习与梯度提升的杰作

🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 ​💫个人格言: "如无必要,勿增实体" 文章目录 XGBoost: 强化学习与梯度提升的杰作引言1. XGBoost概览1.1 什么是XGBoost&#…

玄机平台应急响应—apache日志分析

1、前言 apache的日志一共有两个,一个是access.log,这个日志记录了所有对Web服务器的访问,被入侵时重点排查这个。另一个是error.log,错误日志记录了服务器运行期间遇到的各种错误,以及一些普通的诊断信息&#xff0c…

Java——IO流(一)-(1/8):File、IO流概述、File文件对象的创建(介绍、实例演示)

目录 File IO流概述 File文件对象的创建 介绍 实例演示 File 存储数据的方案 变量 double money 9999.5 数组 int[] age new int[100];对象 Student s new Student()集合 List<Student> students new ArrayList<>()…

NIST 电子病历中的疾病列表部分的认证

美国国家标准与技术研究院&#xff08;National Institute of Standards and Technology&#xff0c;NIST&#xff09;对电子病历的认证 分几个阶段&#xff0c;每个阶段又分门诊和住院&#xff0c;然后又分若干模块。下面是疾病列表的测试脚本。 170.302c_Problemlist Test …

Maven中的DependencyManagement和Dependencies

Maven中的DependencyManagement和Dependencies Dependencies Dependencies是Maven项目中用来声明项目依赖的部分。在pom.xml文件中的<dependencies>部分&#xff0c;你可以直接列出项目所依赖的库&#xff08;artifacts&#xff09;。每个依赖通常包括以下信息&#xf…

DevExpress winForm gridView 设置复选框并可多选

OptionsSelection.MultiSelect True OptionsSelection.MultiSelectMode CheckBoxRowSelect

Leetcode3171. 找到按位与最接近 K 的子数组

Every day a Leetcode 题目来源&#xff1a;3171. 找到按位与最接近 K 的子数组 解法1&#xff1a;位运算 优化&#xff1a; 代码&#xff1a; /** lc appleetcode.cn id3171 langcpp** [3171] 找到按位与最接近 K 的子数组*/// lc codestart class Solution { public:int m…