Redis 篇-深入了解基于 Redis 实现消息队列(比较基于 List 实现消息队列、基于 PubSub 发布订阅模型之间的区别)
🔥博客主页: 【小扳_-CSDN博客】
❤感谢大家点赞👍收藏⭐评论✍
文章目录
1.0 消息队列的认识
2.0 基于 List 实现消息队列
2.1 基于 List 实现消息队列的优缺点
3.0 基于 PubSub 实现消息队列
3.1 基于 PubSub 的消息队列优缺点
4.0 基于 Stream 实现消息队列
4.1 Stream 的单消费模式
4.2 Stream 的消费组模式
1.0 消息队列的认识
消息队列(Message Queue),字面意思就是存放消息的队列。最简单的消息队列模型包含 3 个角色:
1)消息队列:存储和管理消息,也被称为消息代理(Message Broker)
2)生产者:发送消息到消息队列。
3)消费者:从消息队列获取消息并处理消息。
2.0 基于 List 实现消息队列
Redis 的 list 数据结构是一个双向链表,很容易模拟出队列效果。
实现思路:
队列时入口和出口不在一边,因此我们可以利用:LPUSH 结合 RPOP 或者 RPUSH 结合 LPOP 来实现。不过需要注意的是,当队列中没有消息时 RPOP 或 LPOP 操作会直接返回 null ,并不像 JVM 的阻塞队列那样会阻塞并等待消息,因此这里应该使用 BRPOP 或者 BLPOP 来实现阻塞效果。
代码演示:
当数据要进入队列时,那么可以使用 LPUSH KEY VALUE 命令,KEY 为队列名称,VALUE 为数据值,将数据写入 Redis 中。当要获取数据的时,使用 BRPOP KEY TIMEOUT命令,KEY 为队列名称,TIMEOUT 为最大阻塞时间,在最大阻塞时间内,仍旧没有获取数据,则返回 null 。该命令主要做了两步,将数据移除队列中,并将该数据返回。
2.1 基于 List 实现消息队列的优缺点
优点:
1)利用 Redis 存储,不受限于 JVM 内存上限。
2)基于 Redis 的持久化机制,数据安全性有保证。
3)可以满足消息有序性。
缺点:
1)无法避免消息丢失。
当在 BRPOP 获取数据的时候,出现异常,返回数据失败,从而导致数据丢失。因为数据已经从队列中移除出来了,所以队列中已经不存在之前的数据了。
2)只支持单消费者。
当一个消费者来消费之后,其他再来的消费者就不能再获取到第一个消费者的数据,所以说数据只能给一个消费者。
3.0 基于 PubSub 实现消息队列
PubSub 是 Redis2.0 版本引入的消息传递模型。顾名思义,消费者可以订阅一个或多个 channel ,生产者向对应 channel 发送消息后,所有订阅者都能收到相关消息。
常用的命令:
1)SUBSCRIBE channel [channel]:订阅一个或者多个频道。
2)PUBLISH channel msg:向一个频道发送消息。
3)PSUBSCRIBE pattern [pattern]:订阅与 pattern 格式匹配的所有频道。* 代表通配符,订阅所有频道。
这就实现了支持多个消费者获取到相同的消息。当消息被发布了,那么已经订阅该频道的消费者就可以及时获取到消息了。
代码演示:
先订阅频道:
发送消息:
当生产者发送完消息,消费者就会收到通知,从通道中获取到消息。
3.1 基于 PubSub 的消息队列优缺点
优点:
1)采用发布订阅模型,支持多生产、多消费。
解决了基于 List 实现的消息队列的缺点,单消费。
缺点:
1)不支持数据持久化。
将消息发布出去之后,不会进行数据保存。不管有无消费者订阅,都会将消息直接发布出去。
2)无法避免消息丢失。
因为不支持持久化,当消息丢失之后,无法再找到原本的数据。
3)消息堆积有上限,超出时数据丢失。
在消费者中,接收到的数据会暂时存放起来,一旦超过存放的大小,就会导致数据丢失。
4.0 基于 Stream 实现消息队列
Stream 是 Redis 5.0 引入的一种新数据类型,可以实现一个功能非常完善的消息队列。
发送消息的命令:
XADD key ID field string [field string ...]
key 为队列名称,*|ID 为消息的唯一 id,* 代表由 Redis 自动生成。格式是“时间戳-递增数字”,例如 "1644804662707-0"。field value 代表发送到队列中的消息,称为 Entry 。格式就是多个 key-value 键值对。
代码演示:
4.1 Stream 的单消费模式
单消费者获取数据的命名:
XREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] ID [ID ...]
COUNT count 为每次读取消息的最大数量;BLOCK milliseconds 代表当没有消息时,是否阻塞,阻塞时长;STREAMS key 代表要从哪个队列读取消息,key 就是队列名;ID 代表起始 id ,只返回大于该 ID 的消息,0 为从第一个消息开始,而 $ 为从最新的消息开始。
代码演示:
当 ID 使用 $ 时,不会从原本 s 中直接获取原本的数据,而是在 2 秒内有无最新的数据添加进来,如果有,则返回该数据;如果没有,则返回 null。
当 ID 使用 0 时,则从原本 s 中直接获取原本的数据。
在业务开发中,我们可以循环的调用 XREAD 阻塞方式来查询最新消息,从而实现持续监听队列的效果,伪代码如下:
需要注意的地方:
当使用 Stream 单消费者模式的时候,我们指定起始 ID 为 $ 时,代表读取最新的消息,如果我们处理一条消息的过程中,又有超过 1 条以上的消息到达队列,则下次获取时也只能获取到最新的一条,会出现漏读消息的问题。
XREAD 命令特点:
1)消息可回溯。
2)一个消息可以被多个消费者读取。
3)可以阻塞读取。
4)有消息漏读的风险。
4.2 Stream 的消费组模式
将多个消费者划分到一个组中,监听同一个队列。
特点:
1)消息分流:
队列中的消息会分流给组内的不同消费者,而不是重复消费,从而加快消息处理的速度。
2)消息标示:
消费者组会维护一个标示,记录最后一个被处理的消息,哪怕消费者宕机重启,还会从标示之后读取消息。确保每一个消息都会被消费。
3)消息确认:
消费者获取消息后,消息处于 pending 状态,并存入一个 pending-list 。当处理完成后,需要通过 XACK 来确认消息,标记消息为已处理,才会从 pending-list 移除。
创建消费者组:
XGROUP CREATE key groupname id|$ [MKSTREAM]
key 代表队列名称,groupName 代表消费者组名称,ID 起始 ID 标示,$ 代表队列中最后一个消息,0 则代表队列中第一个消息。MKSTREAMS 代表不存在时自动创建队列。
如果之前列表的数据要继续获取,则 ID 选为 0;如果之前的列表中的数据不需要了,则 ID 选为 $ 。
从消费者组读取消息:
XREADGROUP GROUP group consumer [COUNT count] [BLOCK milliseconds] [NOACK] STREAMS key [key ...] ID [ID ...]
group 代表组名,consumer 代表组内消费者名称,count 代表每次读取的最大数量,milliseconds 代表当没有消息时最长的等待时间,NOACK 代表无需手动 ACK,获取消息后自动确认。key 代表指定队列名称,
ID 代表获取消息的起始 ID :
当 ID 为 ">" :从下一个未消费的消息开始。
当 ID 为其他:根据指定 id 从 pending-list 中获取已消费但未确认的消息,例如 0,是从 pending-list 中的第一个消息开始。
确认消息:
XACK key groupName ID
key 为队列名,groupName 为组名,ID 为消息唯一 id 。
查看未确认的消息:
XPENDING key group [start end count] [consumer]
key 为队列名,group 为组名,start 起始地址,count 个数,consumer 组内消费者名称。
消费者监听消息思路:
Java 代码实现从消息队列中获取消息:
import cn.hutool.core.bean.BeanUtil; import com.project.volunteermanagementproject.pojo.StreamObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.connection.stream.*; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component;import java.time.Duration; import java.util.List; import java.util.Map; @Component public class StreamUtil {@AutowiredStringRedisTemplate stringRedisTemplate;//实现从消息队列中获取消息public void getStream(){while (true){try {List<MapRecord<String, Object, Object>> read = stringRedisTemplate.opsForStream().read(Consumer.from("g1", "c1"),StreamReadOptions.empty().count(1).block(Duration.ofSeconds(2)),StreamOffset.create("s1", ReadOffset.lastConsumed()));if (read == null || read.isEmpty()){//如果获取失败,说明没有消息,继续下一次循环continue;}//解析消息中的消息MapRecord<String, Object, Object> entries = read.get(0);Map<Object, Object> value = entries.getValue();StreamObject streamObject = BeanUtil.fillBeanWithMap(value, new StreamObject(), true);//这就拿到了消息队列中的数据了,就可以去使用该对象了System.out.println(streamObject);//这就需要确认消息队列stringRedisTemplate.opsForStream().acknowledge("s1", "g1", entries.getId());} catch (Exception e) {//如果在获取消息过程中出现异常,则需要再次执行该消息任务while (true){try {List<MapRecord<String, Object, Object>> read = stringRedisTemplate.opsForStream().read(Consumer.from("g1", "c1"),StreamReadOptions.empty().count(1),StreamOffset.create("s1", ReadOffset.from("0")));if (read == null || read.isEmpty()){break;}MapRecord<String, Object, Object> entries = read.get(0);Map<Object, Object> value = entries.getValue();StreamObject streamObject = BeanUtil.fillBeanWithMap(value, new StreamObject(), true);//重新拿到未确认的数据System.out.println(streamObject);//再次进行消息确认Long acknowledge = stringRedisTemplate.opsForStream().acknowledge("s1", "g1", entries.getId());} catch (Exception ex) {throw new RuntimeException(ex);}}}}} }
XREADGROUP 命令特点:
1)消息可回溯
2)可以多消费者争抢消息,加快消费速度
3)可以阻塞读取
4)没有消息漏读的风险
5)有消息确认机制,保证消息至少被消费一次
相关文章:

Redis 篇-深入了解基于 Redis 实现消息队列(比较基于 List 实现消息队列、基于 PubSub 发布订阅模型之间的区别)
🔥博客主页: 【小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录 1.0 消息队列的认识 2.0 基于 List 实现消息队列 2.1 基于 List 实现消息队列的优缺点 3.0 基于 PubSub 实现消息队列 3.1 基于 PubSub 的消息队列优缺点 4.0 基于 St…...

python 学习一张图
python学习一张图,python的特点的是学的快,一段时间不用,忘记的也快,弄一张图及一些入门案例吧。 写一个简单的测试: #!/usr/bin/python # -*- coding: UTF-8 -*- import osdef add_num(a, b):return a bif __name__…...
通过Docker部署 MongoDB 服务器
今天我们将在三丰云的免费服务器上进行 MongoDB 的部署测试。这款不错的免费服务器提供了很好的性能,1核CPU、1G内存、10G硬盘和5M带宽,足以满足我们的基本需求。三丰云的服务稳定,操作简单,真是一个值得推荐的选择,特…...

无人机避障雷达技术详解
随着无人机技术的飞速发展,其应用领域已经从最初的军事领域扩展到商业、农业、建筑巡检、应急救援、物流运输等多个领域。在这些多样化的应用场景中,无人机的安全性和稳定性显得尤为重要。无人机避障技术作为保障无人机安全飞行的核心技术之一࿰…...

2009-2023年上市公司华证esg评级评分数据(年度+季度)(含细分项)
2009-2023年上市公司华证esg评级评分数据(年度季度)(含细分项) 1、时间:2009-2023年 2、来源:整理自wind 3、指标:证券代码、年份、证券简称、评级日期、综合评级、综合得分、E评级、E得分、…...
C++ 模板进阶知识——stdenable_if
目录 C 模板进阶知识——std::enable_if1. 简介和背景基本语法使用场景 2. std::enable_if 的基本用法示例:限制函数模板只接受整数类型 3. SFINAE 和 std::enable_if示例:使用 SFINAE 进行函数重载SFINAE 的优点应用场景 4. 在类模板中使用 std::enable…...

国内外ChatGPT网站集合,无限制使用【2024-09最新】~
经过我一年多以来,使用各种AI工具的体验,我收集了一批AI工具和站点 这些工具都是使用的最强最主流的模型,也都在各个领域里都独领风骚的产品。 而且,这些工具你都可以无限制地使用。 无论你是打工人、科研工作者、学生、文案写…...
如何在VUE3中使用函数式组件
在Vue 3中,函数式组件的概念与Vue 2相似,但实现方式有所不同。函数式组件是一种无状态、无实例的组件,它们只根据传入的props和context来渲染输出。在Vue 3中,你可以通过定义一个函数并返回一个渲染函数来使用函数式组件。但是&am…...
linux访问外网的设置
Ubuntu | LUCKFOX WIKI 开发板配置 添加路由信息 sudo route add default gw 172.32.0.100添加 DNS servers 打开文件 sudo vi /etc/resolv.conf添加以下内容: nameserver 8.8.8.8联网测试 ping www.baidu.com开机自动配置 路由信息和 DNS servers 重启后会被清除,我们创建…...

PHP轻松创建高效收集问卷调查小程序系统源码
轻松创建,高效收集 —— 问卷调查小程序,你的调研神器! 一、告别繁琐,一键开启调研之旅 还在为设计问卷、收集数据而头疼不已吗?现在,有了“问卷调查小程序”,一切都变得轻松简单!无…...

Redis面试必问:Redis为什么快?Redis五大基本数据类型
请记住胡广一句话,所有的中间件所有的框架都是建立在基础之上,数据结构,计算机网络,计算机原理大伙一定得看透!!~ 1. Redis快的秘密 相信大部分Redis初学者都会忽略掉一个重要的知识点,Redis…...
InternVL2- dockerfile环境变量持久化使用`ENV`而不是`RUN export`来设置环境变量,以确保环境变量在容器运行时仍然可用
在Dockerfile中使用RUN export命令设置环境变量并不是一种持久化的方式。当你在Dockerfile中使用export命令时,它只会在当前构建阶段生效,并不会被持久化到生成的镜像中。这是因为export命令实际上是在shell环境中设置环境变量,而Docker构建过…...

Python(PyTorch和TensorFlow)图像分割卷积网络导图(生物医学)
🎯要点 语义分割图像三层分割椭圆图像脑肿瘤图像分割动物图像分割皮肤病变分割多模态医学图像多尺度特征生物医学肖像多类和医学分割通用图像分割模板腹部胰腺图像分割分类注意力网络病灶边界分割气胸图像分割 Python生物医学图像卷积网络 该网络由收缩路径和扩…...

DevOps实现CI/CD实战(七)- Jenkins集成k8s实现自动化CI
自动化CI操作 1. 安装gitlab plugin 工具 ##### 2. 配置流水线任务的构建触发器,复制URL:http://192.168.201.111:8080/project/pipeline 3. Gitlab配置Webhooks,将上面的url:http://192.168.201.111:8080/project/pipeline粘…...
从ES6到ES2023 带你深入了解什么是ES
从ES6到ES2023,我们深入探索ECMAScript(简称ES)的演变与发展,了解这一JavaScript标准背后的技术革新和进步。ECMAScript作为JavaScript的标准化版本,每年都在不断推出新版本,为开发者带来更加丰富和强大的功…...
openVX加速-常见问题:适用场景、AI加速、安装方式等
1. 哪些算法处理推荐使用 OpenVX OpenVX 是非常适合图像处理和计算机视觉任务的框架,特别是在需要高性能和硬件加速的场景下。如果你的前处理和后处理涉及到图像滤波、边缘检测、颜色转换等操作,使用 OpenVX 可以带来性能提升。 OpenVX 更适合处理以下…...

国产芯片LT8711HE:TYPE-C/DP1.2转HDMI2.0转换器,4k60Hz高分辨率
以下为LT8711HE芯片的简单介绍,如有介绍不尽之处,请指出 LT8711HE是一个高性能的Type-C/DP1.2到HDMI2.0转换器,用于连接USB Type-C源或DP1.2源到HDMI2.0接收器。 LT8711HE集成了一个DP1.2兼容的接收器和一个HDMI2.0兼容的发射器。另外&…...

论文翻译:arxiv-2024 Benchmark Data Contamination of Large Language Models: A Survey
Benchmark Data Contamination of Large Language Models: A Survey https://arxiv.org/abs/2406.04244 大规模语言模型的基准数据污染:一项综述 文章目录 大规模语言模型的基准数据污染:一项综述摘要1 引言 摘要 大规模语言模型(LLMs&…...

Java+Swing用户信息管理系统
JavaSwing用户信息管理系统 一、系统介绍二、功能展示1.管理员登陆2.用户信息查询3.用户信息添加4.用户信息修改5.用户信息删除 三、系统实现1.UserDao .java 四、其它1.其他系统实现 一、系统介绍 该系统实现了管理员系统登陆、用户信息查询、用户信息添加、用户信息修改、用…...

数据结构基础详解(C语言): 栈的括号匹配(实战)与栈的表达式求值特殊矩阵的压缩存储
文章目录 栈的应用1.栈的括号匹配代码实战:问题分析:2.栈的表达式求值2.1 中缀、后缀、前缀表达式2.2 中缀表达式改写为后缀表达式(手算)2.3 后缀表达式的计算(手算)2.4 中缀表达式转前缀表达式(手算)和计算前缀表达式2.5后缀表达式的计算(机算)2.6 中缀表达式转后缀…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)
要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...

tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...

MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)
macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 🍺 最新版brew安装慢到怀疑人生?别怕,教你轻松起飞! 最近Homebrew更新至最新版,每次执行 brew 命令时都会自动从官方地址 https://formulae.…...

论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing
Muffin 论文 现有方法 CRADLE 和 LEMON,依赖模型推理阶段输出进行差分测试,但在训练阶段是不可行的,因为训练阶段直到最后才有固定输出,中间过程是不断变化的。API 库覆盖低,因为各个 API 都是在各种具体场景下使用。…...

系统掌握PyTorch:图解张量、Autograd、DataLoader、nn.Module与实战模型
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文通过代码驱动的方式,系统讲解PyTorch核心概念和实战技巧,涵盖张量操作、自动微分、数据加载、模型构建和训练全流程&#…...

Ubuntu系统多网卡多相机IP设置方法
目录 1、硬件情况 2、如何设置网卡和相机IP 2.1 万兆网卡连接交换机,交换机再连相机 2.1.1 网卡设置 2.1.2 相机设置 2.3 万兆网卡直连相机 1、硬件情况 2个网卡n个相机 电脑系统信息,系统版本:Ubuntu22.04.5 LTS;内核版本…...