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

java每日精进 2.20 MQ相关复健

在 RabbitMQ 中,消息消费者对消息的签收(acknowledgment)可以通过三种方式进行管理:自动签收手动签收拒绝签收。它们主要控制消费者如何处理消息确认和消息的重新排队。下面详细讲解它们的区别,并通过代码示例展示。

1. 自动签收(Auto Acknowledgment)

在自动签收模式下,RabbitMQ 会在消息被传递到消费者时自动进行消息确认(acknowledge),无需消费者明确地通知 RabbitMQ 消息已经被成功处理。这意味着只要消费者接受到消息,它就认为消息已成功处理并确认。

  • 优点
    • 消费者的代码较为简单,不需要手动确认。
  • 缺点
    • 如果消费者处理消息时发生错误,RabbitMQ 已经认为消息被成功处理,可能会导致消息丢失或无法重新投递。
2. 手动签收(Manual Acknowledgment)

在手动签收模式下,消费者需要显式地通知 RabbitMQ 消息已经被成功处理。消费者通过调用 channel.basicAck() 来手动确认消息。这种模式提供了更大的控制,可以确保只有在消息成功处理后才确认消息。

  • 优点
    • 可以确保消息在处理成功后才会被确认,失败时可以拒绝签收并重新投递。
  • 缺点
    • 需要开发者手动管理确认过程,代码相对复杂。
3. 拒绝签收(Reject Acknowledgment)

拒绝签收指的是消费者告知 RabbitMQ 它无法处理某个消息,可以通过 channel.basicReject()channel.basicNack() 来拒绝该消息。拒绝签收的消息可以被重新投递到队列中或者直接丢弃,具体取决于设置的参数。

  • 优点
    • 可以明确告诉 RabbitMQ 消息无法处理,并且可以选择将消息重新排队,供其他消费者处理。
  • 缺点
    • 如果消息被拒绝并重新排队,可能会导致消息的重复消费。

代码示例

下面展示了 自动签收手动签收拒绝签收 的代码示例。

1. 自动签收(Auto Acknowledgment)
package com.home.consumer;import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;@Component
public class AutoAckConsumer {// 自动签收@RabbitListener(queues = "myQueue", ackMode = "AUTO")public void handleMessage(String msg) {System.out.println("Received message (Auto Acknowledgment): " + msg);// 处理完消息后自动确认}
}

在自动签收模式下,消息会在 handleMessage 方法执行完毕后自动被 RabbitMQ 确认。

2. 手动签收(Manual Acknowledgment)
package com.home.consumer;import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.listener.MessageListener;
import org.springframework.stereotype.Component;@Component
public class ManualAckConsumer {// 手动签收@RabbitListener(queues = "myQueue", ackMode = "MANUAL")public void handleMessage(String msg, Message message) {System.out.println("Received message (Manual Acknowledgment): " + msg);// 处理完消息后显式调用 channel.basicAck() 来确认try {// 消息处理逻辑// 如果处理成功,手动确认消息message.getMessageProperties().getChannel().basicAck(message.getMessageProperties().getDeliveryTag(), false);} catch (Exception e) {// 处理失败时拒绝签收消息message.getMessageProperties().getChannel().basicNack(message.getMessageProperties().getDeliveryTag(), false, true);}}
}

在手动签收模式下,您需要在代码中手动调用 basicAck() 来确认消息,或者在出现错误时使用 basicNack()basicReject() 来拒绝消息。

3. 拒绝签收(Reject Acknowledgment)
package com.home.consumer;import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.listener.MessageListener;
import org.springframework.stereotype.Component;@Component
public class RejectAckConsumer {// 拒绝签收@RabbitListener(queues = "myQueue", ackMode = "MANUAL")public void handleMessage(String msg, Message message) {System.out.println("Received message (Reject Acknowledgment): " + msg);// 如果消息处理失败,则拒绝签收if (msg.contains("error")) {try {// 拒绝消息并重新排队message.getMessageProperties().getChannel().basicReject(message.getMessageProperties().getDeliveryTag(), true);} catch (Exception e) {System.out.println("Failed to reject the message.");}} else {// 处理成功时确认消息try {message.getMessageProperties().getChannel().basicAck(message.getMessageProperties().getDeliveryTag(), false);} catch (Exception e) {System.out.println("Failed to acknowledge the message.");}}}
}

在拒绝签收模式下,当消费者无法处理某个消息时,可以调用 basicReject()basicNack() 来拒绝该消息,并根据需要选择是否将其重新排队。如果选择不重新排队,消息将会丢失。

总结

签收模式描述优点缺点
自动签收消费者收到消息后自动确认代码简洁、开发快速消息处理失败时可能丢失消息
手动签收消费者需要显式确认消息处理成功或失败(使用 basicAck可确保消息成功处理后才确认,失败时可重试或重新排队需要开发者手动管理确认过程,代码复杂
拒绝签收消费者拒绝消息并可选择重新排队或丢弃可以显式地告诉 RabbitMQ 消息无法处理,且重新排队如果不设置合适的重试机制,可能导致消息重复消费

在实际使用时,选择何种签收方式依赖于您的应用需求,通常 手动签收 会提供更好的控制,尤其是在高可靠性需求的场景下。

拒绝签收后的操作

在 RabbitMQ 中,当你使用拒绝签收(basicReject()basicNack())时,可以选择是否将消息重新排队。你可以通过设置相应的参数来决定消息的处理方式。

basicReject() 和 basicNack() 方法的参数

这两个方法允许你传递一个参数,指示是否要重新排队消息:

  • requeue 参数:如果为 true,消息将被重新排队,等待其他消费者消费;如果为 false,消息将不会重新排队,可能会丢失(取决于配置)。

basicReject()

channel.basicReject(deliveryTag, requeue);
  • deliveryTag:是消息的唯一标识符,指示哪条消息被拒绝。
  • requeue:布尔值,指示消息是否应该重新排队。如果为 true,消息将重新排队到队列中;如果为 false,消息将丢失或直接被丢弃。

basicNack()

channel.basicNack(deliveryTag, multiple, requeue);
  • deliveryTag:与 basicReject() 中相同,用于标识消息。
  • multiple:是否拒绝所有比当前 deliveryTag 小的消息。如果为 true,则拒绝多个消息;如果为 false,则仅拒绝当前消息。
  • requeue:与 basicReject() 中相同,控制是否将消息重新排队。
1. 使用 basicReject() 来拒绝并重新排队
package com.home.consumer;import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;@Component
public class RejectAndRequeueConsumer {@RabbitListener(queues = "myQueue", ackMode = "MANUAL")public void handleMessage(String msg, Message message) {System.out.println("Received message (Reject and Requeue): " + msg);// 如果消息处理失败,拒绝消息并重新排队if (msg.contains("error")) {try {// 拒绝并重新排队message.getMessageProperties().getChannel().basicReject(message.getMessageProperties().getDeliveryTag(), true);System.out.println("Message rejected and requeued");} catch (Exception e) {System.out.println("Failed to reject and requeue the message.");}} else {// 处理成功时确认消息try {message.getMessageProperties().getChannel().basicAck(message.getMessageProperties().getDeliveryTag(), false);System.out.println("Message processed successfully and acknowledged");} catch (Exception e) {System.out.println("Failed to acknowledge the message.");}}}
}
  • 打印接收到的消息:首先,输出消息内容 msg

  • 消息失败处理:如果消息内容包含 "error"(通过 msg.contains("error") 检查),认为处理失败,执行以下操作:

    • 拒绝并重新排队:通过 basicReject 方法拒绝消息,且设置 requeue = true,即将消息重新放回队列等待其他消费者处理。此时,RabbitMQ 会重新将消息排入队列,等待下一次消费。
    • 异常处理:如果拒绝和重新排队消息过程中出现异常,捕获异常并打印错误信息。
  • 消息成功处理:如果消息内容没有错误(即不包含 "error"),则认为消息处理成功,执行以下操作:

    • 确认消息:通过 basicAck 方法手动确认消息已成功处理。
    • 异常处理:如果在确认过程中发生异常,捕获并打印错误信息。
2. 使用 basicReject() 来拒绝并丢弃消息
package com.home.consumer;import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;@Component
public class RejectAndDiscardConsumer {@RabbitListener(queues = "myQueue", ackMode = "MANUAL")public void handleMessage(String msg, Message message) {System.out.println("Received message (Reject and Discard): " + msg);// 如果消息处理失败,拒绝消息并丢弃if (msg.contains("error")) {try {// 拒绝并丢弃消息,不重新排队message.getMessageProperties().getChannel().basicReject(message.getMessageProperties().getDeliveryTag(), false);System.out.println("Message rejected and discarded");} catch (Exception e) {System.out.println("Failed to reject and discard the message.");}} else {// 处理成功时确认消息try {message.getMessageProperties().getChannel().basicAck(message.getMessageProperties().getDeliveryTag(), false);System.out.println("Message processed successfully and acknowledged");} catch (Exception e) {System.out.println("Failed to acknowledge the message.");}}}
}
  • 打印接收到的消息:首先输出接收到的消息内容 msg

  • 消息失败处理:如果消息的内容包含 "error"(通过 msg.contains("error") 判断),就认为消息处理失败,并执行以下操作:

    • 拒绝并丢弃消息:通过 basicReject 方法拒绝消息,并且将 requeue 设置为 false,即消息不会重新排回队列,而是直接丢弃。这样,该消息就不会再被其他消费者处理。
    • 异常处理:如果拒绝和丢弃消息时发生异常,则捕获异常并打印错误信息。
  • 消息成功处理:如果消息内容不包含 "error",认为消息处理成功,执行以下操作:

    • 确认消息:通过 basicAck 方法手动确认消息已被成功处理。
    • 异常处理:如果确认消息时发生异常,则捕获并打印错误信息。
3.使用 basicNack() 来拒绝多个消息并重新排队
package com.home.consumer;import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;@Component
public class NackAndRequeueConsumer {@RabbitListener(queues = "myQueue", ackMode = "MANUAL")public void handleMessage(String msg, Message message) {System.out.println("Received message (Nack and Requeue): " + msg);// 如果消息处理失败,拒绝多个消息并重新排队if (msg.contains("error")) {try {// 拒绝多个消息并重新排队message.getMessageProperties().getChannel().basicNack(message.getMessageProperties().getDeliveryTag(), false, true);System.out.println("Message Nacked and requeued");} catch (Exception e) {System.out.println("Failed to nack and requeue the message.");}} else {// 处理成功时确认消息try {message.getMessageProperties().getChannel().basicAck(message.getMessageProperties().getDeliveryTag(), false);System.out.println("Message processed successfully and acknowledged");} catch (Exception e) {System.out.println("Failed to acknowledge the message.");}}}
}
  • 打印接收到的消息:首先输出接收到的消息内容 msg

  • 消息失败处理:如果消息内容包含 "error"(通过 msg.contains("error") 判断),表示消息处理失败,执行以下操作:

    • 拒绝多个消息并重新排队:通过 basicNack 方法拒绝消息,并设置以下参数:
      • multiple = false:表示只拒绝当前消息。如果设置为 true,则会拒绝当前消息以及所有较早的消息。
      • requeue = true:表示将消息重新排回队列等待其他消费者处理。
    • 异常处理:如果在执行 basicNack 时出现异常,捕获异常并打印错误信息。
  • 消息成功处理:如果消息内容不包含 "error",则认为消息处理成功,执行以下操作:

    • 确认消息:通过 basicAck 方法手动确认消息已经成功处理。
    • 异常处理:如果在确认消息时发生异常,捕获并打印错误信息。

basicNackbasicAck 的区别:

  • basicNack:这个方法是用于拒绝消息(与 basicReject 类似)。basicNack 还可以处理多个消息,并允许你选择是否重新排队。与 basicReject 不同,basicNack 能够处理批量拒绝消息。

    • multiple = false:表示仅拒绝当前消息。
    • requeue = true:表示将消息重新排回队列。
  • basicAck:这是用来确认消息已经成功处理的。当消息被成功消费后,消费者需要调用该方法来告诉 RabbitMQ 消息已经被处理,RabbitMQ 可以删除该消息。

相关文章:

java每日精进 2.20 MQ相关复健

在 RabbitMQ 中,消息消费者对消息的签收(acknowledgment)可以通过三种方式进行管理:自动签收、手动签收 和 拒绝签收。它们主要控制消费者如何处理消息确认和消息的重新排队。下面详细讲解它们的区别,并通过代码示例展…...

【设计模式精讲】结构型模式之代理模式(静态代理、JDK动态代理、cglib动态代理)

文章目录 第五章 结构型模式5.1 代理模式5.1.1 代理模式介绍5.1.2 代理模式原理5.1.3 静态代理实现5.1.4 JDK动态代理5.1.4.1 JDK动态代理实现5.1.4.2 类是如何动态生成的5.1.4.3 代理类的调用过程 5.1.5 cglib动态代理5.1.5.1 cglib动态代理实现5.1.5.2 cglib代理流程 5.1.6 代…...

京东广告基于 Apache Doris 的冷热数据分层实践

一、背景介绍 京东广告围绕Apache Doris建设广告数据存储服务,为广告主提供实时广告效果报表和多维数据分析服务。历经多年发展,积累了海量的广告数据,目前系统总数据容量接近1PB,数据行数达到18万亿行,日查询请求量8…...

win11 安装pyenv来管理python

1、使用power shell或者cmd来安装: 2、使用pyenv 发现并没有pyenv。 3、在环境变量中增加: 路径:右键--此电脑--属性--高级系统设置--环境变量--Path--增加刚才--target所在的目录D:\tools\pyenv\pyenv-win\bin。 先退出当前的,…...

【AI】GitHub Copilot

GitHub Copilot 是一款由 GitHub 和 OpenAI 合作开发的 AI 编程助手,它可以在多种开发工具中使用。以下是 GitHub Copilot 支持的主要开发工具和平台: 1. Visual Studio Code (VS Code) 官方支持:GitHub Copilot 在 VS Code 中拥有最完整的集…...

【LeetCode 热题100】76. 最小覆盖子串的算法思路及python代码

76. 最小覆盖子串 给你一个字符串 s s s、一个字符串 t t t。返回 s s s 中涵盖 t t t 所有字符的最小子串。如果 s s s 中不存在涵盖 t t t 所有字符的子串,则返回空字符串 ‘ ‘ " \quad" ‘‘" 。 注意: 对于 t t t 中重复…...

力扣-回溯-17 电话号码的字母组合

思路 和之前的回溯不同的是&#xff0c;要遍历完所有的数字&#xff0c;并且在单层递归逻辑里需要遍历一整个字符串 代码 class Solution { public:vector<string> letters {"", "", "abc", "def", "ghi", "…...

[AHOI2018初中组] 分组---贪心算法

贪心没套路果真如此。 题目描述 小可可的学校信息组总共有 n 个队员&#xff0c;每个人都有一个实力值 ai​。现在&#xff0c;一年一度的编程大赛就要到了&#xff0c;小可可的学校获得了若干个参赛名额&#xff0c;教练决定把学校信息组的 n 个队员分成若干个小组去参加这场…...

知识图谱-学习计划

✨知识图谱知识学习&#xff0c;给我点赞&#xff01;&#x1f31f;&#x1f31f;&#x1f31f; &#x1f31f;什么是知识图谱&#xff1f; 知识图谱是一种通过图结构表示知识的技术&#xff0c;它可以帮助我们更清晰地理解和组织信息。无论是学习、工作还是生活&#xff0c;知…...

网安作业3

标准版 接口ip配置 r2 [r2]interface GigabitEthernet 0/0/0 [r2-GigabitEthernet0/0/0]ip address 13.0.0.3 24 [r2-GigabitEthernet0/0/0]interface GigabitEthernet 0/0/1 [r2-GigabitEthernet0/0/1]ip address 100.1.1.254 24 [r2-GigabitEthernet0/0/1]interface Gigab…...

快速提升网站收录:内容创作的艺术

快速提升网站收录&#xff0c;内容创作是关键。以下是一些关于内容创作以提升网站收录的艺术性建议&#xff1a; 一、关键词研究与优化 选择长尾关键词&#xff1a;进行深入的关键词研究&#xff0c;选择既符合网站主题又具有一定搜索量的长尾关键词。这些关键词通常更具体&a…...

【C语言】CreateFile函数用法介绍

目录 一、函数原型与基本功能 二、参数详解 1. lpFileName&#xff08;文件路径&#xff09; 2. dwDesiredAccess&#xff08;访问权限&#xff09; 补充说明 3. dwShareMode&#xff08;共享模式&#xff09; 5. dwCreationDisposition&#xff08;创建策略&#xff09…...

蓝桥杯好数

样例输入&#xff1a; 24 输出&#xff1a;7 输入&#xff1a;2024 输出&#xff1a; 150 思路&#xff1a;本题朴素方法的时间复杂度是O(n * log10(n)) &#xff0c;不超时。主要考察能否逐位取数&#xff0c;注意细节pi&#xff0c;这样不会改变i,否则会导致循环错误。 #in…...

SOME/IP--协议英文原文讲解10

前言 SOME/IP协议越来越多的用于汽车电子行业中&#xff0c;关于协议详细完全的中文资料却没有&#xff0c;所以我将结合工作经验并对照英文原版协议做一系列的文章。基本分三大块&#xff1a; 1. SOME/IP协议讲解 2. SOME/IP-SD协议讲解 3. python/C举例调试讲解 4.2.2 Req…...

欢乐力扣:赎金信

文章目录 1、题目描述2、 代码 1、题目描述 赎金信&#xff0c;给你两个字符串&#xff1a;ransomNote 和 magazine &#xff0c;判断 ransomNote 能不能由 magazine 里面的字符构成。如果可以&#xff0c;返回 true &#xff1b;否则返回 false 。magazine 中的每个字符只能在…...

【量化科普】Standard Deviation,标准差

【量化科普】Standard Deviation&#xff0c;标准差 &#x1f680;&#x1f680;&#x1f680;量化软件开通&#x1f680;&#x1f680;&#x1f680; &#x1f680;&#x1f680;&#x1f680;量化实战教程&#x1f680;&#x1f680;&#x1f680; 在量化投资领域&#xf…...

stm32单片机个人学习笔记15(I2C通信协议)

前言 本篇文章属于stm32单片机&#xff08;以下简称单片机&#xff09;的学习笔记&#xff0c;来源于B站教学视频。下面是这位up主的视频链接。本文为个人学习笔记&#xff0c;只能做参考&#xff0c;细节方面建议观看视频&#xff0c;肯定受益匪浅。 STM32入门教程-2023版 细…...

网络安全防护

一&#xff1a;物理安全防护 直接的物理破坏所造成的损失远大于通过网络远程攻击 提高物理安全需关注的问题&#xff1a; 1: 服务器和安全设备是否放置在上锁的机房内&#xff1f; 2: 网络设备是否被保护和监控&#xff1f; 3: 是否有无关人员单独在敏感区域工作&…...

YOLOV7的复现过程

复现 YOLOv7 代码的步骤相对清晰&#xff0c;主要分为以下几个部分&#xff1a; 环境准备克隆 YOLOv7 仓库准备数据集训练模型验证和测试推理&#xff08;Inference&#xff09; 下面是一个简化的流程来帮助你复现 YOLOv7 代码&#xff1a; 1. 环境准备 首先&#xff0c;你…...

uniapp实现app的pdf预览

实现效果 文件准备 static下添加该pdf文件&#xff08;下载地址&#xff1a;https://gitee.com/shallow-winds/resource_package/tree/master/%E6%96%B9%E6%B3%95%E4%B8%80/html&#xff09; 使用web-view进行展示&#xff1a; 在这里插入代码片 <web-view :src"u…...

网络编程(Modbus进阶)

思维导图 Modbus RTU&#xff08;先学一点理论&#xff09; 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议&#xff0c;由 Modicon 公司&#xff08;现施耐德电气&#xff09;于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...

Spring Boot 实现流式响应(兼容 2.7.x)

在实际开发中&#xff0c;我们可能会遇到一些流式数据处理的场景&#xff0c;比如接收来自上游接口的 Server-Sent Events&#xff08;SSE&#xff09; 或 流式 JSON 内容&#xff0c;并将其原样中转给前端页面或客户端。这种情况下&#xff0c;传统的 RestTemplate 缓存机制会…...

蓝桥杯3498 01串的熵

问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798&#xff0c; 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

WPF八大法则:告别模态窗口卡顿

⚙️ 核心问题&#xff1a;阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程&#xff0c;导致后续逻辑无法执行&#xff1a; var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题&#xff1a…...

人工智能 - 在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型

在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型。这些平台各有侧重&#xff0c;适用场景差异显著。下面我将从核心功能定位、典型应用场景、真实体验痛点、选型决策关键点进行拆解&#xff0c;并提供具体场景下的推荐方案。 一、核心功能定位速览 平台核心定位技术栈亮…...

前端高频面试题2:浏览器/计算机网络

本专栏相关链接 前端高频面试题1&#xff1a;HTML/CSS 前端高频面试题2&#xff1a;浏览器/计算机网络 前端高频面试题3&#xff1a;JavaScript 1.什么是强缓存、协商缓存&#xff1f; 强缓存&#xff1a; 当浏览器请求资源时&#xff0c;首先检查本地缓存是否命中。如果命…...

Qt的学习(一)

1.什么是Qt Qt特指用来进行桌面应用开发&#xff08;电脑上写的程序&#xff09;涉及到的一套技术Qt无法开发网页前端&#xff0c;也不能开发移动应用。 客户端开发的重要任务&#xff1a;编写和用户交互的界面。一般来说和用户交互的界面&#xff0c;有两种典型风格&…...

aardio 自动识别验证码输入

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

webpack面试题

面试题&#xff1a;webpack介绍和简单使用 一、webpack&#xff08;模块化打包工具&#xff09;1. webpack是把项目当作一个整体&#xff0c;通过给定的一个主文件&#xff0c;webpack将从这个主文件开始找到你项目当中的所有依赖文件&#xff0c;使用loaders来处理它们&#x…...

Python环境安装与虚拟环境配置详解

本文档旨在为Python开发者提供一站式的环境安装与虚拟环境配置指南&#xff0c;适用于Windows、macOS和Linux系统。无论你是初学者还是有经验的开发者&#xff0c;都能在此找到适合自己的环境搭建方法和常见问题的解决方案。 快速开始 一分钟快速安装与虚拟环境配置 # macOS/…...