[RabbitMQ]消息应答概念_消息手动应答代码

消息应答

概念

消费者完成一个任务可能需要一段时间,如果其中一个消费者处理一个长的任务并仅只完成了部分突然它挂掉了,会发生什么情况。RabbitMQ 一旦向消费者传递了一条消息,便立即将该消
息标记为删除。在这种情况下,突然有个消费者挂掉了,我们将丢失正在处理的消息。以及后续发送给该消费这的消息,因为它无法接收到。

为了保证消息在发送过程中不丢失,rabbitmq 引入消息应答机制,消息应答就是:消费者在接收到消息并且处理该消息之后,告诉 rabbitmq 它已经处理了,rabbitmq 可以把该消息删除了。

自动应答

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

消息应答的方法

A.Channel.basicAck(用于肯定确认)
RabbitMQ 已知道该消息并且成功的处理消息,可以将其丢弃了

B.Channel.basicNack(用于否定确认)

C.Channel.basicReject(用于否定确认)
与 Channel.basicNack 相比少一个参数(批量处理参数)
不处理该消息了直接拒绝,可以将其丢弃了

Multiple 的解释

手动应答的好处是可以批量应答并且减少网络拥堵

在这里插入图片描述

multiple 的 true 和 false 代表不同意思

true 代表批量应答 channel 上未应答的消息

  • 比如说 channel 上有传送 tag 的消息 5,6,7,8 当前 tag 是 8 那么此时5-8 的这些还未应答的消息都会被确认收到消息应答

false 同上面相比

  • 只会应答 tag=8 的消息 5,6,7 这三个消息依然不会被确认收到消息应答

在这里插入图片描述

消息应答自动重新入队

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

在这里插入图片描述

消息手动应答代码

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

在这里插入图片描述

消息生产者

package com.atguigu.three;import com.atguigu.utils.RabbitMqUtils;
import com.rabbitmq.client.Channel;import java.util.Scanner;/*** 消息在手动应答时是不丢失,放回队列中重新消费**/
public class Task02 {//队列名称public static final String TASK_QUEUE_NAME = "ack_queue";public static void main(String[] args) throws Exception {Channel channel = RabbitMqUtils.getChannel();//声明队列channel.queueDeclare(TASK_QUEUE_NAME,false,false,false,null);//从控制台中输入信息Scanner scanner = new Scanner(System.in);while(scanner.hasNext()){String message = scanner.next();channel.basicPublish("",TASK_QUEUE_NAME,null,message.getBytes("UTF-8"));System.out.println("生产者发出消息:"+message);}}}

睡眠工具类

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

消费者

package com.atguigu.three;import com.atguigu.utils.RabbitMqUtils;
import com.atguigu.utils.SleepUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;/**** 消息在手动应答时是不丢失,放回队列中重新消费*/
public class Worker03 {//队列名称public static final String TASK_QUEUE_NAME = "ack_queue";//接收消息public static void main(String[] args) throws Exception {Channel channel = RabbitMqUtils.getChannel();System.out.println("C1等待接收消息处理时间较短");DeliverCallback deliverCallback = (cousumerTag,message)->{//沉睡1SSleepUtils.sleep(1);System.out.println("接收到的消息:" + new String(message.getBody(),"UTF-8" ));//手动应答/*** 1.消息的标记 tag* 2.是否批量应答 false:不批量应答信道中的消息 true:批量**/channel.basicAck(message.getEnvelope().getDeliveryTag(),false);};//采用手动应答boolean autoAck = false;channel.basicConsume(TASK_QUEUE_NAME,autoAck,deliverCallback,(consumerTag ->{System.out.println(consumerTag+"消费者取消消费接口回调逻辑");}));}}
package com.atguigu.three;import com.atguigu.utils.RabbitMqUtils;
import com.atguigu.utils.SleepUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;/**** 消息在手动应答时是不丢失,放回队列中重新消费*/
public class Worker04 {//队列名称public static final String TASK_QUEUE_NAME = "ack_queue";//接收消息public static void main(String[] args) throws Exception {Channel channel = RabbitMqUtils.getChannel();System.out.println("C2等待接收消息处理时间较短");DeliverCallback deliverCallback = (cousumerTag,message)->{//沉睡1SSleepUtils.sleep(30);System.out.println("接收到的消息:" + new String(message.getBody(),"UTF-8" ));//手动应答/*** 1.消息的标记 tag* 2.是否批量应答 false:不批量应答信道中的消息 true:批量**/channel.basicAck(message.getEnvelope().getDeliveryTag(),false);};//采用手动应答boolean autoAck = false;channel.basicConsume(TASK_QUEUE_NAME,autoAck,deliverCallback,(consumerTag ->{System.out.println(consumerTag+"消费者取消消费接口回调逻辑");}));}}

手动应答效果演示

正常情况下消息发送方发送两个消息 C1 和 C2 分别接收到消息并进行处理

在这里插入图片描述

在发送者发送消息 dd,发出消息之后的把 C2 消费者停掉,按理说该 C2 来处理该消息,但是由于它处理时间较长,在还未处理完,也就是说 C2 还没有执行 ack 代码的时候,C2 被停掉了,此时会看到消息被 C1 接收到了,说明消息 dd 被重新入队,然后分配给能处理消息的 C1 处理了

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

rust火箭基地主楼开启方法_Rust 为什么能成为 Stack Overflow 最受欢迎的语言?

每年,开发者问答网站 Stack Overflow 都会对程序员社区展开年度调查,包括他们最喜爱的技术到工作偏好的所有内容。 在2017 年和2018 年Stack Overflow 年度开发者调查中,Rust语言已经连续两年成为最受欢迎语言Top 1。2018 年 Stack Overflow …

[RabbitMQ]队列持久化

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

微服务认证架构如何演进来的?

【答疑解惑】| 作者 / Edison Zhou这是恰童鞋骚年的第267篇原创内容之前有同事问为何要用基于JWT令牌的认证架构,然后近期又有童鞋在后台留言问微服务安全认证架构的实践,因此我决定花两篇推文来解答一下。为了答好这个话题,我们先来看看微服…

maskrcnn还可以加网络吗_绿茶加蜂蜜的功效,绿茶可以加蜂蜜吗?

绿茶是我国的主要茶类之一,是一种天然健康的饮料,蜂蜜也是一种营养丰富的滋补食品,有些人不喜欢绿茶的苦味,想放点蜂蜜中和一下,但是不知道能不能这样做。那么绿茶能不能加蜂蜜呢?蜂蜜的主要成分是葡萄糖、果糖&#…

三分钟Docker-镜像、容器实战篇

本文主要内容:Docker 镜像、容器 常用命令整理使用Docker常见命令,搭建Consul集群通过创建自定义镜像,把.NetCore Api运行在Docker中1.镜像、容器命令镜像序号命令描述1docker image build基于Dockerfile创建镜像2docker image history显示镜…

手机键鼠映射软件_吃鸡,我最专业!---盖世小鸡键鼠吃鸡套装评测

Hello大家好,欢迎浏览这篇评测贴。首先很荣幸能够参与本期的评测,毕竟如此炫酷富有科技感的装备是可遇而不可求的,所以不论是得知入选还是收到快递开箱的时候,心情都是无比激动。话不多说,接下来就让我带你走进这个不一…

[Redis6]Redis启动_前台启动和后台启动

前台启动(不推荐) 前台启动,命令行窗口不能关闭,否则服务器停止 redis-server 关闭redis ctrlC : 关闭 后台启动(推荐) 备份redis.conf cd redis-6.2.6/cp redis.conf /etc/redis.confcd /etc后台启动设置daemonize no改成y…

深入剖析.NETCORE中CORS(跨站资源共享)

前言由于现代互联网的飞速发展,我们在开发现代 Web 应用程序中,经常需要考虑多种类型的客户端访问服务的情况;而这种情况放在15年前几乎是不可想象的,在那个时代,我们更多的是考虑怎么把网页快速友好的嵌套到服务代码中…

ai进入轮廓模式怎么退出_详解AI中扩展、扩展外观、轮廓化描边、创建轮廓

详解AI中扩展、扩展外观、轮廓化描边、创建轮廓在学习AI软件中,有不少同学分不清扩展、扩展外观、轮廓化描边、创建轮廓这四个概念具体的功能区别,今天我们具体聊一下。先说“扩展”,扩展是把复杂物体拆分成最基本的路径。矢量物体在组合&…

[Redis6]Redis相关知识介绍

Redis介绍相关知识 端口6379 6379 是 "MERZ " 九宫格输入法对应的数字。Alessia Merz 是一位意大利舞女、女演员。 Redis 作者 Antirez 早年看电视节目,觉得 Merz 在节目中的一些话愚蠢可笑,Antirez 喜欢造“梗”用于平时和朋友们交流&#x…

【Power Automate】如何自动生成Word与PDF文件[上]

上半年已经悄悄溜走,因为疫情,大家似乎也很习惯于在家办公。作为业务人员,如何汇报自己的工作,让自己更多地学习和掌握数字化办公技巧至关重要。那么今天我们就来看一下在不使用代码的情况下,如何通过Power Automate自…

easyui datagrid 中怎么选中所有页面的数据_学会这5个Excel中常用技巧,可以准时下班去摆摊了...

Excel是大家常用的办公工具之一,虽说上手简单,但是想要精通还是要下一些功夫的。最近有些小伙伴在留言吐槽说Excel数据处理时很方便,但是操作起来还是挺费时间的,其实工作是离不开技巧的,今天要跟大家分享的5个Excel技…

五年了,别再把务虚会开 “虚” 了

这是头哥侃码的第210篇原创上个月,为了配合公司的半年度战略讨论会,我特意留出一个周六的时间,与几位Leader在公司的会议室里开了一次部门半年度务虚会。让我没想到的是,几位小伙伴在这次讨论过程中都表现得非常亢奋,所…

人工智能正在如何改变传统行业

做了这么多年的技术工作,也正好赶上了这一波的人工智能浪潮,有时候我总是不免在想,人工智能如何真正地融入到我们的日常工作和生活中,实现它应有的价值。大家可能不知道,人工智能其实最早在上个世纪五十年代就提出来了…

[Redis6]key键操作

我们先连接redis cd /usr/local/bin/ redis-cliRedis键(key) keys *查看当前库所有key (匹配:keys *1) exists key判断某个key是否存在 type key 查看你的key是什么类型 del key 删除指定的key数据 unlink key 根据value选择非阻塞删除 仅将keys从keyspace元数据…

继续分享 5 个实用的 vs 调试技巧

前言我在上一篇文章????《5 个非常实用的 vs 调试技巧》 中分享了 5 个我认为非常值得了解的 vs 调试技巧,本周继续分享 5 个很基础但同样实用的调试技巧。1. 条件断点作用简介:顾名思义,带条件的断点。满足条件才中断。条件断点非常非常…

[Redis6]常用数据类型_String字符串

Redis字符串(String) 简介 String是Redis最基本的类型,你可以理解成与Memcached一模一样的类型,一个key对应一个value。String类型是二进制安全的。意味着Redis的string可以包含任何数据。比如jpg图片或者序列化的对象。String类型是Redis最基本的数据…

在ASP.NET Core中创建自定义端点可视化图

在上篇文章中,我为构建自定义端点可视化图奠定了基础,正如我在第一篇文章中展示的那样。该图显示了端点路由的不同部分:文字值,参数,动词约束和产生结果的端点:在本文中,我将展示如何通过创建一…

[Redis6]常用数据类型_List列表

List列表 简介 单键多值 Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。 它的底层实际是个双向链表,对两端的操作性能很高,通过索…

[Redis6]常用数据类型_Set集合

Set集合 简介 Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个s…