RabbitMQ之消息应答和持久化

文章目录

  • 前言
  • 一、消息应答
    • 1.概念
    • 2.自动应答
    • 3.消息应答方法
    • 4.Multiple 的解释
    • 5.消息自动重新入队
    • 6.消息手动应答代码
    • 7.手动应答效果演示
  • 二、RabbitMQ持久化
    • 1.概念
    • 2.队列如何实现持久化
    • 3.消息实现持久化
    • 4.不公平分发
    • 5.预取值
  • 总结


前言

在RabbitMQ中,我们的消费者在应答方面有需要注意的地方,接下来就跟我博主一起去了解一下吧!


一、消息应答

1.概念

  • 消费者完成一个任务可能需要一段时间,如果其中一个消费者处理一个长的任务并仅只完成了部分突然它挂掉了,会发生什么情况。RabbitMQ 一旦向消费者传递了一条消息,便立即将该消息标记为删除。在这种情况下,突然有个消费者挂掉了,我们将丢失正在处理的消息。以及后续发送给该消费这的消息,因为它无法接收到。
  • 为了保证消息在发送过程中不丢失,rabbitmq 引入消息应答机制,消息应答就是:消费者在接收到消息并且处理该消息之后,告诉 rabbitmq 它已经处理了,rabbitmq 可以把该消息删除了

2.自动应答

消息发送后立即被认为已经传送成功,这种模式需要在高吞吐量和数据传输安全性方面做权衡,因为这种模式如果消息在接收到之前,消费者那边出现连接或者 channel 关闭,那么消息就丢失了,当然另一方面这种模式消费者那边可以传递过载的消息,没有对传递的消息数量进行限制,当然这样有可能使得消费者这边由于接收太多还来不及处理的消息,导致这些消息的积压,最终使得内存耗尽,最终这些消费者线程被操作系统杀死,所以这种模式仅适用在消费者可以高效并以某种速率能够处理这些消息的情况下使用

3.消息应答方法

  • A.Channel.basicAck(用于肯定确认),RabbitMQ 已知道该消息并且成功的处理消息,可以将其丢弃了
  • B.Channel.basicNack(用于否定确认)
  • C.Channel.basicReject(用于否定确认),与 Channel.basicNack 相比少一个参数,不处理该消息了直接拒绝,可以将其丢弃了

4.Multiple 的解释

手动应答的好处是可以批量应答并且减少网络拥堵
在这里插入图片描述

  • multiple 的 true 和 false 代表不同意思
    • true 代表批量应答 channel 上未应答的消息
      • 比如说 channel 上有传送 tag 的消息 5,6,7,8 当前 tag 是 8 那么此时5-8 的这些还未应答的消息都会被确认收到消息应答
    • false 同上面相比
      • 只会应答 tag=8 的消息 5,6,7 这三个消息依然不会被确认收到消息应答

在这里插入图片描述
在这里插入图片描述

5.消息自动重新入队

如果消费者由于某些原因失去连接(其通道已关闭,连接已关闭或 TCP 连接丢失),导致消息
未发送 ACK 确认,RabbitMQ 将了解到消息未完全处理,并将对其重新排队。如果此时其他消费者
可以处理,它将很快将其重新分发给另一个消费者。这样,即使某个消费者偶尔死亡,也可以确
保不会丢失任何消息。
在这里插入图片描述

6.消息手动应答代码

默认消息采用的是自动应答,所以我们要想实现消息消费过程中不丢失,需要把自动应答改为手动应答,消费者在上面代码的基础上增加下面画红色部分代码。
在这里插入图片描述

消息生产者

public class Task02 {private static final String TASK_QUEUE_NAME = "ack_queue";public static void main(String[] argv) throws Exception {try (Channel channel = RabbitMqUtils.getChannel()) {channel.queueDeclare(TASK_QUEUE_NAME, false, false, false, null);Scanner sc = new Scanner(System.in);System.out.println("请输入信息");while (sc.hasNext()) {String message = sc.nextLine();channel.basicPublish("", TASK_QUEUE_NAME, null, message.getBytes("UTF-8"));System.out.println("生产者发出消息" + message);}}}
}

消费者01

public class Work03 {private static final String ACK_QUEUE_NAME="ack_queue";public static void main(String[] args) throws Exception {Channel channel = RabbitMqUtils.getChannel();System.out.println("C1 等待接收消息处理时间较短");//消息消费的时候如何处理消息DeliverCallback deliverCallback=(consumerTag,delivery)->{String message= new String(delivery.getBody());SleepUtils.sleep(1);System.out.println("接收到消息:"+message);/*** 1.消息标记 tag* 2.是否批量应答未应答消息*/channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);};//采用手动应答boolean autoAck=false;channel.basicConsume(ACK_QUEUE_NAME,autoAck,deliverCallback,(consumerTag)->{System.out.println(consumerTag+"消费者取消消费接口回调逻辑");});}
}

消费者02

public class Work04 {private static final String ACK_QUEUE_NAME="ack_queue";public static void main(String[] args) throws Exception {Channel channel = RabbitMqUtils.getChannel();System.out.println("C2 等待接收消息处理时间较长");//消息消费的时候如何处理消息DeliverCallback deliverCallback=(consumerTag,delivery)->{String message= new String(delivery.getBody());SleepUtils.sleep(30);System.out.println("接收到消息:"+message);/*** 1.消息标记 tag* 2.是否批量应答未应答消息*/channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);};//采用手动应答boolean autoAck=false;channel.basicConsume(ACK_QUEUE_NAME,autoAck,deliverCallback,(consumerTag)->{System.out.println(consumerTag+"消费者取消消费接口回调逻辑");});}
}

睡眠工具类

public class SleepUtils {public static void sleep(int second){try {Thread.sleep(1000*second);} catch (InterruptedException _ignored) {Thread.currentThread().interrupt();}}
}

7.手动应答效果演示

正常情况下消息发送方发送两个消息 C1 和 C2 分别接收到消息并进行处理
在这里插入图片描述
在发送者发送消息 dd,发出消息之后的把 C2 消费者停掉,按理说该 C2 来处理该消息,但是由于它处理时间较长,在还未处理完,也就是说 C2 还没有执行 ack 代码的时候,C2 被停掉了,此时会看到消息被 C1 接收到了,说明消息 dd 被重新入队,然后分配给能处理消息的 C1 处理了。
在这里插入图片描述

二、RabbitMQ持久化

1.概念

刚刚我们已经看到了如何处理任务不丢失的情况,但是如何保障当 RabbitMQ 服务停掉以后消息生产者发送过来的消息不丢失。默认情况下 RabbitMQ 退出或由于某种原因崩溃时,它忽视队列和消息,除非告知它不要这样做。确保消息不会丢失需要做两件事:我们需要将队列和消息都标记为持久化

2.队列如何实现持久化

之前我们创建的队列都是非持久化的,rabbitmq 如果重启的化,该队列就会被删除掉,如果要队列实现持久化 需要在声明队列的时候把 durable 参数设置为持久化
在这里插入图片描述但是需要注意的就是如果之前声明的队列不是持久化的,需要把原先队列先删除,或者重新创建一个持久化的队列,不然就会出现错误
在这里插入图片描述
以下为控制台中持久化与非持久化队列的 UI 显示区
在这里插入图片描述
这个时候即使重启 rabbitmq 队列也依然存在。

3.消息实现持久化

要想让消息实现持久化需要在消息生产者修改代码,MessageProperties.PERSISTENT_TEXT_PLAIN 添加这个属性。
在这里插入图片描述
将消息标记为持久化并不能完全保证不会丢失消息。尽管它告诉 RabbitMQ 将消息保存到磁盘,但是这里依然存在当消息刚准备存储在磁盘的时候 但是还没有存储完,消息还在缓存的一个间隔点。此时并没有真正写入磁盘。持久性保证并不强,但是对于我们的简单任务队列而言,这已经绰绰有余了。

4.不公平分发

在最开始的时候我们学习到 RabbitMQ 分发消息采用的轮训分发,但是在某种场景下这种策略并不是很好,比方说有两个消费者在处理任务,其中有个消费者 1 处理任务的速度非常快,而另外一个消费者 2处理速度却很慢,这个时候我们还是采用轮训分发的化就会到这处理速度快的这个消费者很大一部分时间处于空闲状态,而处理慢的那个消费者一直在干活,这种分配方式在这种情况下其实就不太好,但是RabbitMQ 并不知道这种情况它依然很公平的进行分发。

为了避免这种情况,我们可以设置参数 channel.basicQos(1);

在这里插入图片描述
在这里插入图片描述

意思就是如果这个任务我还没有处理完或者我还没有应答你,你先别分配给我,我目前只能处理一个任务,然后 rabbitmq 就会把该任务分配给没有那么忙的那个空闲消费者,当然如果所有的消费者都没有完成手上任务,队列还在不停的添加新任务,队列有可能就会遇到队列被撑满的情况,这个时候就只能添加新的 worker 或者改变其他存储任务的策略。

5.预取值

本身消息的发送就是异步发送的,所以在任何时候,channel 上肯定不止只有一个消息另外来自消费者的手动确认本质上也是异步的。因此这里就存在一个未确认的消息缓冲区,因此希望开发人员能限制此缓冲区的大小,以避免缓冲区里面无限制的未确认消息问题。这个时候就可以通过使用 basic.qos 方法设置“预取计数”值来完成的。该值定义通道上允许的未确认消息的最大数量。一旦数量达到配置的数量,RabbitMQ 将停止在通道上传递更多消息,除非至少有一个未处理的消息被确认,例如,假设在通道上有未确认的消息 5、6、7,8,并且通道的预取计数设置为 4,此时 RabbitMQ 将不会在该通道上再传递任何消息,除非至少有一个未应答的消息被 ack。比方说 tag=6 这个消息刚刚被确认 ACK,RabbitMQ 将会感知这个情况到并再发送一条消息。消息应答和 QoS 预取值对用户吞吐量有重大影响。通常,增加预取将提高向消费者传递消息的速度。虽然自动应答传输消息速率是最佳的,但是,在这种情况下已传递但尚未处理的消息的数量也会增加,从而增加了消费者的 RAM 消耗(随机存取存储器)应该小心使用具有无限预处理的自动确认模式或手动确认模式,消费者消费了大量的消息如果没有确认的话,会导致消费者连接节点的内存消耗变大,所以找到合适的预取值是一个反复试验的过程,不同的负载该值取值也不同 100 到 300 范围内的值通常可提供最佳的吞吐量,并且不会给消费者带来太大的风险。预取值为 1 是最保守的。当然这将使吞吐量变得很低,特别是消费者连接延迟很严重的情况下,特别是在消费者连接等待时间较长的环境中。对于大多数应用来说,稍微高一点的值将是最佳的。
在这里插入图片描述

总结

以上就是RabbitMQ之消息应答和持久化的相关知识,希望对你有所帮助。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SQL题

[极客大挑战 2019]EasySQL 进行简单的尝试,就知道是单引号的字符型注入 万能密码进行一个简单的尝试 结果就出来了 还是要了解一下原理 输入的是1,形成的sql语句是错误的SELECT*FROM table_name WHERE username1and password123; 第一个单引号和第二个…

01Urllib

1.什么是互联网爬虫? 如果我们把互联网比作一张大的蜘蛛网,那一台计算机上的数据便是蜘蛛网上的一个猎物,而爬虫程序就是一只小蜘蛛,沿着蜘蛛网抓取自己想要的数据 解释1:通过一个程序,根据Url(http://www.…

Flutter应用-使用sqflite升级数据库

文章目录 问题描述具体做法代码示例更多条件限制升级 数据库迁移和备份简介数据库迁移数据库备份 问题描述 使用fluttter开发的应用程序发布后,发现数据库有些设计不合理。如何来更新数据库呢? 使用sqflite来处理数据库,但是第一版软件发布后…

JQuery ajax 提交数据提示:Uncaught TypeError:Illegal invocation

JQuery ajax 提交数据提示:Uncaught TypeError:Illegal invocation 1 问题描述 用jQuery Ajax向DRF接口提交数据的时候,console提示:Uncaught TypeError:Illegal invocation(未捕获的异常:非法调用)。 这个问题可能有两种原因导…

Zookeeper学习笔记(1)—— 基础知识

Zookeeper概述 Zookeeper 是一个开源的分布式的,为分布式框架提供协调服务的 Apache 项目 工作机制 Zookeeper从设计模式角度来理解:是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受…

【AI视野·今日Robot 机器人论文速览 第六十三期】Thu, 26 Oct 2023

AI视野今日CS.Robotics 机器人学论文速览 Fri, 27 Oct 2023 Totally 27 papers 👉上期速览✈更多精彩请移步主页 Daily Robotics Papers 6-DoF Stability Field via Diffusion Models Authors Takuma Yoneda, Tianchong Jiang, Gregory Shakhnarovich, Matthew R. …

微软Surface/Surface pro笔记本电脑进入bios界面

微软Surface笔记本电脑进入bios界面 方法一推薦這種方法:Surface laptop 进BIOS步骤 开机后,不停按音量键进bios界面。 方法二:Surface Book、Surface Pro进bios步骤 1、关闭Surface,然后等待大约10秒钟以确保其处于关闭状态。…

SQL中的数据类型和规范化,助力数据存储优化

大家好,目前优化数据存储对于获得良好的性能始终至关重要,选择合适的数据类型并应用正确的规范化过程对于决定其性能至关重要。本文将介绍最重要和最常用的数据类型和规范化过程。 一、SQL中的数据类型 SQL中主要有两种数据类型:字符串和数…

小程序action-sheet结合自定义tabbar显示

要实现此效果,遇到的问题:背景在电脑端调试的情况正常的情况下,手机端点击事件工单,返回回来的时候action-sheet卡住在屏幕上,点击遮罩层都不消失。更奇怪的是 这种情况并不是每次发生,而是有时候发生&…

给VSCode插上一双AI的翅膀

#AI编程助手哪家好?DevChat“真”好用# 文章目录 前言一、安装DevChat1.1、访问地址1.2、注册1.3、在VSCode里安装DevChat插件1.3.1、未安装状态1.3.2、已安装状态 二、设置Access Key2.1. 点击左下角管理(“齿轮”图标)—命令面板&#xff…

DNS域名解析服务

1.概述 1.1.产生原因 IP 地址:是互联网上计算机唯一的逻辑地址,通过IP 地址实现不同计算机之间的相互通信,每台联网计算机都需要通过I 地址来互相联系和分别,但由于P 地址是由一串容易混淆的数字串构成,人们很难记忆所有计算机的…

【7】Spring Boot 3 集成组件:缓存组件 spring cache + spring data redis

目录 【7】Spring Boot 3 集成组件:缓存组件 spring cache spring data redis什么是缓存抽象声明式注解JSR-107对应SpEL上下文数据 引入依赖cache 支持的缓存类型缓存类型配置NONESIMPLEREDIS自定义配置 CAFFEINE Hazelcast...总结 个人主页: 【⭐️个人主页】 需要…

企业邮箱认证指南:安全与高效的邮箱认证方法

企业邮箱是专门为企业提供的电子邮件服务,安全性和专业性更高。在开始使用企业邮箱之前,很多人会有一些问题,比如企业邮箱需要认证吗、如何开通企业邮箱,以及哪款企业邮箱好。 1、企业邮箱在使用前需要认证吗? 答案是肯…

esp-01刷固件/下载软件到内部单片机的方法

此文章为转载,非原创 一、准备 需要准备三个东西: 1.esp模块。ESP-01 和 ESP-01s 的引脚及 flash 容量基本完全兼容,只是内部硬件设计粗糙与否的区别,所以理论上都适用。 2.官方固件。此部分可以从安信可官方教程中下载&#xff0…

MySQL库的操作『增删改查 ‖ 编码问题 ‖ 备份与恢复』

✨个人主页: 北 海 🎉所属专栏: MySQL 学习 🎃操作环境: CentOS 7.6 阿里云远程服务器 🎁软件版本: MySQL 5.7.44 文章目录 1.创建数据库2.数据库中的编码问题2.1.字符集与校验集2.3.支持的字符…

数据结构:AVLTree的插入和删除的实现

个人主页 : 个人主页 个人专栏 : 《数据结构》 《C语言》《C》 文章目录 前言一、AVLTree二、AVLTree的插入插入新增节点调整平衡因子旋转左单旋(新增节点位于较高右子树的右侧)右单旋(新增节点位于较高左子树的左侧)右左双旋(新增节点在较高右子树的左子…

Unity中Shader雾效的实现方法三

文章目录 前言一、声明雾效所需要的内置变体二、在 v2f 中,定义 float4 worldPos :TEXCOORD1三、在顶点着色器中添加,会自动取o.worldPos.w裁剪空间下的坐标z值.在这里插入图片描述 四、在片元着色器,添加以下两句话1、UNITY_EXTR…

三江城115m²3室2厅2卫,现代简约不单是居所更是对生活的向往。福州中宅装饰,福州装修

【前言】 简洁有力,静默无声。 以简约精致的方式,展现现代都市生活; 经典不因潮流褪色,不为悦人只为悦己。 项目信息 项目名称 | 三江城 设计地址 | 福建福州 项目面积 | 115㎡ 项目户型 | 3室2厅 设计风格 | 现代简约 全…

LeetCode(23)找出字符串中第一个匹配项的下标【数组/字符串】【简单】

目录 1.题目2.答案3.提交结果截图 链接: 找出字符串中第一个匹配项的下标 1.题目 给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 hays…

黑马程序员微服务第四天课程 分布式搜索引擎1

分布式搜索引擎01 – elasticsearch基础 0.学习目标 1.初识elasticsearch 1.1.了解ES 1.1.1.elasticsearch的作用 elasticsearch是一款非常强大的开源搜索引擎,具备非常多强大功能,可以帮助我们从海量数据中快速找到需要的内容 例如: …