首页 > 其他分享 >RabbitMQ总结

RabbitMQ总结

时间:2024-10-24 09:59:50浏览次数:7  
标签:总结 队列 RabbitMQ 重试 次数 死信 消息

重试机制

背景

  • 线上的系统(Spring Boot 2.2.11,rabbitmq为3.2.0),某一天突然有大量的错误日志写入,进几台服务器的硬盘都写满了。查看日志发现是RabbitMQ的消费者在接收消息消费时,抛出了异常错误,此时会不断重新进入消费重新打印错误日志,循环如此进硬盘写满了。

RabbitMQ的消息重试机制,也就是消息失败后进行重试,重试机制是默认开启的,但是如果没有重试机制相关的配置会导致消息一直无间隔的重试,直到消费成功,所以要使用重试机制一定要有相关配置。

例如,原配置如下:

spring.rabbitmq:
  addresses: 10.xxx.xxx.67:5672,10.xxx.xxx.130:5672,10.xxx.xxx.28:5672
  username: admin
  password: admi232ewd$@!32
  virtual-host: /
  # 发布确认模式:配置消息到达交换器的确认回调
  publisher-confirm-type: correlated
  # 发布返回消息:配置消息到达队列的回调
  publisher-returns: true
  # 配置消费端-手动签收,也可在 @RabbitListener 注解中设置参数 ackMode="MANUAL" 开启
  # listener.simple.acknowledge-mode: manual
  # 消息预读数量 1表示每次从队列中读取一条消息
  # listener.simple.prefetch: 1
  listener:
    simple:
      auto-startup: true

这里配置是没有限制重试次数的,因此需要重试次数限制

抛异常消费者:

@Component
@Slf4j(topic = "logger-mq-common#ProcessCompletedEventConsumer")
@RabbitListener(queues = "${spring.rabbitmq.queues-configs.process.event.completed}")
public class ProcessCompletedEventConsumer {
	  @RabbitHandler
    public void process(Map message) {
		    log.info("接收到一个【测试消息重试次数】消息:{}", JSONUtil.toJsonStr(message));
		    JSONObject obj = null;
        // 这里抛异常就一直rabbitmq重新尝试消费
				Assert.isTrue(obj != null, () -> new ApiException("实例不存在"));
    }
}

自动ACK + RabbitMQ重试机制

 .....
  listener:
    simple:
      auto-startup: true
      # ACK模式(默认为auto)
      acknowledge-mode: auto
      # 开启重试
      retry:
        enabled: true
        max-attempts: 3
        initial-interval: 5000

当ACK模式是自动时,达到最大重试上限后,消息会发送到死信队列

死信就是消息在特定场景下的一种表现形式,这些场景包括:

  • 消息被拒绝(basic.reject / basic.nack),并且requeue = false
  • 消息的 TTL 过期时
  • 消息队列达到最大长度
  • 达到最大重试限制

消息在这些场景中时,被称为死信

死信队列就是用于储存死信的消息队列,在死信队列中,有且只有死信构成,不会存在其余类型的消息。死信队列也是一个普通队列,也可以被消费者消费,区别在于业务队列需要绑定在死信队列上,才能正常地把死信发送到死信队列上。

设置之后,消费者抛异常重试次数也就受到限制。

手动ACK + 手动重试

另外,如果acknowledge-mode是manual,在抛出异常的时候仍会触发重试,但是达到重试上限之后,会永远处于Unacked状态,不会进入到死信队列,必须要手动拒绝才可以进入死信队列,所以说这里不用配置重试机制而是采用手动重试的方式。

/**
 * 消息最大重试次数
 */
private static final int MAX_RETRIES = 3;
 
/**
 * 重试间隔(秒)
 */
private static final long RETRY_INTERVAL = 5;
 
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
	
@RabbitListener(queues = RabbitMqConfig.USER_ADD_QUEUE, concurrency = "10")
public void userAddReceiver(String data, Message message, Channel channel) throws IOException, InterruptedException {
	UserVo vo = OBJECT_MAPPER.readValue(data, UserVo.class);
	// 重试次数
	int retryCount = 0;
	boolean success = false;
    // 消费失败并且重试次数<=重试上限次数
	while (!success && retryCount < MAX_RETRIES) {
		retryCount++;
		// 具体业务逻辑
		success = messageHandle(vo);
		// 如果失败则重试
		if (!success) {
			String errorTip = "第" + retryCount + "次消费失败" +
					((retryCount < 3) ? "," + RETRY_INTERVAL + "s后重试" : ",进入死信队列");
			log.error(errorTip);
			Thread.sleep(RETRY_INTERVAL * 1000);
		}
	}
	if (success) {
		// 消费成功,确认
		channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
		log.info("创建订单数据消费成功");
	} else {
		// 重试多次之后仍失败,进入死信队列
		channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
		log.info("创建订单数据消费失败");
	}
}

总结:两种方案都可以达到我们的预期效果,相比起来方案一会更加的方便简洁,方案二的可控性更高

参考: https://blog.csdn.net/cwr452829537/article/details/124967634

标签:总结,队列,RabbitMQ,重试,次数,死信,消息
From: https://www.cnblogs.com/chq3272991/p/18498962

相关文章

  • 2024.10.23总结+CSP2024前总结
    赛时T1看完一脸懵逼啊,画了好几个立方体,一直觉得切四刀是14块,然后也找不到什么规律,就去看后面的题了,jsy说是15之后还是没想法,只觉着\(7=2^3-1\),\(15=2^4-1\),当\(n<=m\)时是\(2^n\),后来看回来把已知情况全列出来,找到\(f[i][j]=f[i][j-1]+f[i-1][j-1]\)的递推式,写了60pts的,但WA了......
  • Springboot知识点总结
    一、传统使用配置文件方式创建Java对象:1、创建一个普通的Maven项目,并加入依赖:<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.1</version></dependency>&......
  • 2024年10月23日总结
    今天继续学习了数据库的连接,这是今日总结完成的模版(还有一些地方有问题)packagemapper;importjava.sql.Connection;importjava.sql.DriverManager;importjava.sql.PreparedStatement;importjava.sql.SQLException;publicclassstudentsystemmapper{Connectionconn=n......
  • MyBatis-Plus知识点总结
    官方文档:https://baomidou.com/introduce/ 快速开始1.引入MyBatis-PlusStarter依赖<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.7</version></......
  • 在使用 RabbitMQ 作为消息代理时,多个 Celery 实例(或应用)可以共享同一个 RabbitMQ 实例
    在使用RabbitMQ作为消息代理时,多个Celery实例(或应用)可以共享同一个RabbitMQ实例。这样做可以简化基础设施管理,同时允许不同的Celery应用之间进行消息传递和协作。下面是如何配置多个Celery实例以使用同一个RabbitMQ实例的步骤:1.安装依赖确保你的Python环......
  • RabbitMQ是一个开源的消息代理和队列服务器
    RabbitMQ是一个开源的消息代理和队列服务器,它基于AMQP(AdvancedMessageQueuingProtocol,高级消息队列协议)协议实现,同时也支持其他消息协议如STOMP、MQTT等。作为一个可靠的消息传递服务,RabbitMQ在分布式系统中广泛应用于异步处理、应用解耦、流量控制等场景。以下是对Rabb......
  • 20241023 模拟赛总结
    期望得分:100+100+0+20=220实际得分:100+0+0+0=100(满昏)这算哪门子信心赛……分挂没了,懒得喷。T1人机分类讨论题。T2一眼二分答案,二分最终的最小的最大值,记bi表示把i这个位置加到至少ai需要多少次,然后手玩不知道多少组发现每个位置至少要操作一次,那机器人的启动位置是无......
  • 学期2024-2025-1 学号20241424 《计算机基础与程序设计》第5周学习总结
    学期2024-2025-1学号20241424《计算机基础与程序设计》第5周学习总结作业信息|这个作业属于2024-2025-1-计算机基础与程序设计)||-- |-- ||这个作业要求在|(https://www.cnblogs.com/rocedu/p/9577842.html#WEEK05))||这个作业的目标|<参考上面的学习总结模板,把学习过程通过......
  • 华为鸿蒙HarmonyOS第一课-学习笔记总结
    华为鸿蒙HarmonyOS第一课-学习笔记总结一、概述目前华为开发者联盟下属的HarmonyOS官网推出了,针对HarmonyOS应用开发的学习视频。总共13课程,干货满满。每节课程后会有练习题,分数达成后会有结课证书。最终所有课程都学习后,可以去考试,获取HarmonyOS基础开发者证书。华为官方学习课程......
  • 2024/10/23 模拟赛总结
    \(100+55+30+0=185\),T4没有-1唐完了#A.GCD把\(1\sim50\)的\(f\)打表输出,可以找到规律:若\(x\)为\(p^k(k\in\mathbb{N}^+,p\in\mathcal{P})\),则\(f(x)=p\),否则\(f(x)=1\)于是可以筛出所有质数并枚举指数//BLuemoon_#include<bits/stdc++.h>usingnamespaces......