当前位置: 首页 > news >正文

【中间件系列】浅析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消息队列也是一个不错的选择。

相关文章:

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

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

[NOVATEK] NT96580行车记录仪功能学习笔记

一、u-Boot升级灯 运行u-Boot程序时LED灯闪烁,找到运行过程中一直在运行的函数在里面进行LED引脚电平的翻转 宏定义 Z:\SunFan\AHD580\pip\na51055_PIP\BSP\u-boot\include\configs\nvt-na51055-evb.h Z:\SunFan\AHD580\pip\na51055_PIP\BSP\u-boot\drivers\mtd\nvt_flash_…...

创新案例 | AI数据驱动下的全域数字化转型的五大关键洞见

近年来通过全域数字化转型在竞争激烈的市场中脱颖而出。传统零食行业面临市场竞争加剧和消费者需求多样化的挑战,如何利用数据驱动和AI技术,能更好地实现会员运营效率和用户满意度的显著提升呢?本文将探讨全域数字化转型的五大关键洞见&#…...

学习笔记——网络参考模型——TCP/IP模型(网络层)

三、TCP/IP模型-网络层 1、IPV4报头 (1)IPV4报文格式 IP Packet(IP数据包),其包头主要内容如下∶ Version版本∶4 bit,4∶表示为IPv4; 6∶表示为IPv6。 Header Length首部长度∶4 bit,代表IP报头的长度(首部长度),如果不带Opt…...

AI初识--LLM、ollama、llama都是些个啥?

LLM全称(large language model)也就是大语言模型 什么是Ollama,它与Llama是什么关系? Ollama是一个开源的 LLM(大型语言模型)服务工具,用于简化在本地运行大语言模型,降低使用大语…...

【全开源】JAVA打车小程序APP打车顺风车滴滴车跑腿源码微信小程序打车源码

:构建便捷出行新体验 一、引言:探索打车系统小程序源码的重要性 在数字化快速发展的今天,打车系统小程序已成为我们日常生活中不可或缺的一部分。它以其便捷、高效的特点,极大地改变了我们的出行方式。而背后的关键,…...

LeetCode 两数之和 + 三数之和

两数之和 简单题 思路:一个Map,key是数值,value是该数值对应的下标,遍历的时候判断一下当前数组下标对应的值在map里有没有可组合成target的(具体体现为在map里找target-nums【i】),如果有,直接…...

Switch刷机:安装Android系统和Linux系统

文章目录 Switch刷机解锁SwitchSwitchroot重要提示 安装Android系统安装Linux系统(Ubuntu)安装Lakka系统安装多系统(和大气层系统、官方原生系统并存) Switch刷机 解锁Switch 刷机的前提是要解锁bootloader,早期的NS…...

DeepDriving | 多目标跟踪算法之SORT

本文来源公众号“DeepDriving”,仅用于学术分享,侵权删,干货满满。 原文链接:多目标跟踪算法之SORT 1 简介 SORT是2016年发表的一篇文章《Simple Online and Realtime Tracking》中提出的一个经典的多目标跟踪算法,…...

实验演示方波是由正弦波叠加而成的

方波可以看成是由N个正弦波叠加而成,在数学上,方波可以写成这个式子,大家可以看到这个式子里面包含了无数个奇数次的正弦波。 下面通过运放构成的反相求和电路来看一下,正弦波叠加成方波 对于这个反相求和电路: Ui1是…...

进口电动流量调节阀的选型-美国品牌

进口电动流量调节阀的选型需要综合考虑多个因素,以确保所选阀门能够满足实际应用需求。以下是选型时需要考虑的主要方面: 一、明确应用需求 工作介质:了解介质的性质,包括流体类型、温度、压力以及是否具有腐蚀性或特殊性质。流…...

【人工智能】流行且重要的智能算法整理

✍🏻记录学习过程中的输出,坚持每天学习一点点~ ❤️希望能给大家提供帮助~欢迎点赞👍🏻收藏⭐评论✍🏻指点🙏 小记: 今天在看之前写的文档时,发现有人工智能十大算法的内容&#xf…...

webrtc客户端测试和arm平台测试(待补充)

一、关于API的使用研究 二、遇到的一些问题 1、snd_write Broken pipe 写音频数据到缓存不及时导致,codec没有数据可以播放。 alsa总结 WebRTC源码研究(1)WebRTC架构 WebRTC 中的基本音频处理操作...

Unity ShaderGraph 扭曲

需要注意的是: HDRP ShaderGraph中 你不能扭曲UI,所以假如你要扭曲视频,请把视频在材质上渲染 播放,这样就可以扭曲视频了喔, ShaderGraph扭曲...

鸿蒙Ability Kit(程序框架服务)【应用启动框架AppStartup】

应用启动框架AppStartup 概述 AppStartup提供了一种更加简单高效的初始化组件的方式,支持异步初始化组件加速应用的启动时间。使用启动框架应用开发者只需要分别为待初始化的组件实现AppStartup提供的[StartupTask]接口,并在[startup_config]中配置App…...

DBeaver添加DM8驱动(maven下载和jar包下载配置)

DBeaver 24.0.3添加DM8驱动 下载DBeaver下载DM达梦驱动下载 安装配置使用自带Dameng自行添加达梦驱动 因为最近公司项目有信创要求,所以下载了达梦数据库。使用自带的达梦管理工具不是很方便,于是换了DBeaver。 哼哧哼哧安装好后,创建数据库连…...

EXCEL多sheet添加目录跳转

EXCEL多sheet添加目录跳转 背景 excel中有几十个sheet,点下方左右切换sheet太耗时,希望可以有根据sheet名超链接跳转相应sheet,处理完后再跳回原sheet。 方案一 新建目录sheet,在A1写sheet名,右键选择最下方超链接…...

MySQL之查询性能优化(十)

查询性能优化 MySQL查询优化器的局限性 松散索引扫描 由于历史原因,MySQL并不支持松散索引扫描,也就无法按照不连续的方式扫描一个索引。通常,MySQL的索引扫描需要先定义一个起点和终点,即使需要的数据只是这段索引中很少数的几…...

短视频矩阵源码----如何做正规开发规则分享:

一、什么是SaaS化服务技术开发? (短视频矩阵系统是源头开发的应该分为3个端口---- 总后台控制端、总代理端口,总商户后台) SaaS是软件即服务(Software as a Service)的缩写。它是一种通过互联网提供软件应…...

4. JavaScript 循环与迭代

JavaScript 中提供了这些循环语句&#xff1a; for 语句do … while 语句while 语句label 语句 跳出多级循环 var num 0; outPoint: for (var i 0; i < 10; i) {for (var j 0; j < 10; j) {if (i 5 && j 5) {break outPoint; // 在 i 5&#xff0c;j 5 …...

关于nvm与node.js

1 安装nvm 安装过程中手动修改 nvm的安装路径&#xff0c; 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解&#xff0c;但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后&#xff0c;通常在该文件中会出现以下配置&…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...

Python ROS2【机器人中间件框架】 简介

销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行

项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战&#xff0c;克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...

mac 安装homebrew (nvm 及git)

mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用&#xff1a; 方法一&#xff1a;使用 Homebrew 安装 Git&#xff08;推荐&#xff09; 步骤如下&#xff1a;打开终端&#xff08;Terminal.app&#xff09; 1.安装 Homebrew…...

Axure 下拉框联动

实现选省、选完省之后选对应省份下的市区...

macOS 终端智能代理检测

&#x1f9e0; 终端智能代理检测&#xff1a;自动判断是否需要设置代理访问 GitHub 在开发中&#xff0c;使用 GitHub 是非常常见的需求。但有时候我们会发现某些命令失败、插件无法更新&#xff0c;例如&#xff1a; fatal: unable to access https://github.com/ohmyzsh/oh…...

aardio 自动识别验证码输入

技术尝试 上周在发学习日志时有网友提议“在网页上识别验证码”&#xff0c;于是尝试整合图像识别与网页自动化技术&#xff0c;完成了这套模拟登录流程。核心思路是&#xff1a;截图验证码→OCR识别→自动填充表单→提交并验证结果。 代码在这里 import soImage; import we…...

【R语言编程——数据调用】

这里写自定义目录标题 可用库及数据集外部数据导入方法查看数据集信息 在R语言中&#xff0c;有多个库支持调用内置数据集或外部数据&#xff0c;包括studentdata等教学或示例数据集。以下是常见的库和方法&#xff1a; 可用库及数据集 openintro库 该库包含多个教学数据集&a…...