RabbitMQ的消息可靠性(五)
一、可靠性问题分析
在前面说过消息的传递过程中有三个对象参与分别是:生产者、RabbitMQ(broker)、消费者;接下来就是要围绕这三个对象来分析消息在传递过程中会在哪些环节出来可靠性问题;
1.1、生产者丢失消息
生产者发送消息到broker时,要保证消息的可靠性,主要的方案有以下2种:
1.事务
2.confirm机制
1.1.1、事务
RabbitMQ提供了事务功能,也即在生产者发送数据之前开启RabbitMQ事务,然后再发送消息,如果消息没有成功发送到RabbitMQ,那么就抛出异常,然后进行事务回滚,回滚之后再重新发送消息,如果RabbitMQ接收到了消息,那么进行事务提交,再开始发送下一条数据。
优点
保证消息一定能够发送到RabbitMQ中,发送端不会出现消息丢失的情况;
缺点
事务机制是阻塞(同步)的,每次发送消息必须要等到mq回应之后才能继续发送消息,比较耗费性能,会导致吞吐量降下来
1.1.2、confirm模式
基于事务的特性,作为补偿,RabbitMQ添加了消息确认机制,也即confirm机制。confirm机制和事务机制最大的不同就是事务是同步的,confirm是异步的,发送完一个消息后可以继续发送下一个消息,mq接收到消息后会异步回调接口告知消息接收结果。生产者开启confirm模式后,每次发送的消息都会分配一个唯一id,如果消息成功发送到了mq中,那么就会返回一个ack消息,表示消息接收成功,反之会返回一个nack,告诉你消息接收失败,可以进行重试。依据这个机制,我们可以维护每个消息id的状态,如果超过一定时间还是没有接收到mq的回调,那么就重发消息。
1.1.3、confirm模式代码演示
其实这块代码在前面几篇文章的代码中有体现过;下面以springboot集成的方式再演示一种
pom.xml文件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--web包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
application.yml
spring:
rabbitmq: #rabbitmq 连接配置
publisher-confirm-type: correlated # 开启confirm确认模式
host: 192.168.0.1
port: 5672
username: admin
password: admin server:
port: 8081
@Component
public class ConfirmCallbackService implements RabbitTemplate.ConfirmCallback {
/***
* @param correlationData 相关配置信息
* @param ack exchange交换机 是否成功收到了消息。true 成功,false代表失败
* @param cause 失败原因
* */
@Override
public void confirm(CorrelationData correlationData ,boolean ack ,String cause) { if (ack){
//消息发送成功
System.out.println ("消息发送成功到交换机");
}else{
System.out.println ("发送失败"+cause);
}
}
}
/**
* 定义队列和交换机
*/
@Configuration
public class QueueConfig {
@Bean(name="confirmTestExchange")
public FanoutExchange confirmTestExchange(){
return new FanoutExchange("confirmTestExchange",true,false);
}
@Bean(name = "confirmTestQueue")
public Queue confirmTestQueue(){
return new Queue("confirm_test_queue",true,false,false);
} @Bean
public Binding confirmTestFanoutExcangeAndQueue(@Qualifier("confirmTestQueue")Queue queue,@Qualifier("confirmTestExchange") FanoutExchange fanoutExchange){
return BindingBuilder.bind(queue).to(fanoutExchange);
}
}
@RestController
@RequestMapping(value = "/producer")
@CrossOrigin
public class Producer {
@Autowired
private RabbitTemplate rabbitTemplate; @Autowired
private ConfirmCallbackService confirmCallbackService; @Autowired
private ReturnCallbackService returnCallbackService;
@GetMapping
public void producer(){ rabbitTemplate.setConfirmCallback ( confirmCallbackService );
rabbitTemplate.convertAndSend ( "confirmTestExchange","","测试RabbitTemplate功能" );
}
}

上面演示了消息投放到交换机的案例,下面演示一个消息从 exchange–>queue 投递失败则会返回一个 returnCallback的案例;生产端通过实现ReturnCallback接口,启动消息失败返回,消息路由不到队列时会触发该回调接口
spring:
rabbitmq: #rabbitmq 连接配置
publisher-confirm-type: correlated # 开启confirm确认模式
publisher-returns: true #开启退回模式
host: 192.168.0.1
port: 5672
username: admin
password: admin server:
port: 8081
rabbitTemplate.setMandatory(true);
@Component
public class ReturnCallbackService implements RabbitTemplate.ReturnCallback {
/**
*
* @param message 消息对象
* @param i 错误码
* @param s 错误信息
* @param s1 交换机
* @param s2 路由键
*/
@Override
public void returnedMessage(Message message ,int i ,String s ,String s1 ,String s2) {
System.out.println("消息对象:" + message);
System.out.println("错误码:" + i);
System.out.println("错误信息:" + s);
System.out.println("消息使用的交换器:" + s1);
System.out.println("消息使用的路由key:" + s2);
//业务代码处理
}
}
yml配置
spring:
rabbitmq: #rabbitmq 连接配置
publisher-confirm-type: correlated # 开启confirm确认模式
publisher-returns: true #开启退回模式
host: 124.71.33.75
port: 5672
username: admin
password: ghy20200707rabbitmq server:
port: 8081
public void producerLose(){
/**
*确保消息发送失败后可以重新返回到队列中
*/
rabbitTemplate.setMandatory(true);
/**
* 消息投递确认模式
*/
rabbitTemplate.setConfirmCallback(confirmCallbackService);
/**
* 消息投递到队列失败回调处理
*/
rabbitTemplate.setReturnCallback(returnCallbackService);
CorrelationData correlationData = new CorrelationData("id_"+System.currentTimeMillis()+"");
//发送消息
rabbitTemplate.convertAndSend("directExchange", "RabbitTemplate","测试RabbitTemplate功能" ,correlationData);
}
测试接口

1.2、消费者丢失消息
其实在生产者和消费者中间,rabbitmq也是会丢失消息的,解决方案就是持久化存储,这个方案在前面有讲过;所以在这里就跳过;下面直接说消息确认机制ack,ack指Acknowledge确认。 表示消费端收到消息后的确认方式
- AcknowledgeMode.NONE:不确认
- AcknowledgeMode.AUTO:自动确认
- AcknowledgeMode.MANUAL:手动确认
spring:
rabbitmq: #rabbitmq 连接配置
publisher-confirm-type: correlated # 开启confirm确认模式
publisher-returns: true #开启退回模式
host: 124.71.33.75
port: 5672
username: admin
password: ghy20200707rabbitmq
listener:
simple:
acknowledge-mode: manual #手动确认 server:
port: 8081
/**
* 消费者消息确认机制
*/
@Component
@RabbitListener(queues = "confirm_test_queue")
public class ReceiverMessage {
@RabbitHandler
public void processHandler(String msg,Channel channel,Message message) throws IOException {
long deliveryTag = message.getMessageProperties().getDeliveryTag();
try {
System.out.println("消息内容" + new String(message.getBody()));
//TODO 具体业务逻辑
// 手动签收[参数1:消息投递序号,参数2:批量签收]
channel.basicAck(deliveryTag, true);
} catch (Exception e) {
//拒绝签收[参数1:消息投递序号,参数2:批量拒绝,参数3:是否重新加入队列]
channel.basicNack(deliveryTag, true, true);
}
}
}
要想测试异常很简单,在代码加一个报错语句就可以测试了,我这里就不搞事了;
二、消费端限流
2.1、TTL
三、死信队列
- 队列消息长度到达限制;
- 消费者拒接消费消息,basicNack/basicReject,并且不把消息重新放入原目标队列,requeue=false;
- 原队列存在消息过期设置,消息到达超时时间未被消费;
四、延迟队列

RabbitMQ的消息可靠性(五)的更多相关文章
- [转载]RabbitMQ消息可靠性分析
有很多人问过我这么一类问题:RabbitMQ如何确保消息可靠?很多时候,笔者的回答都是:说来话长的事情何来长话短说.的确,要确保消息可靠不只是单单几句就能够叙述明白的,包括Kafka也是如此.可靠并不 ...
- RabbitMQ消息可靠性分析 - 简书
原文:RabbitMQ消息可靠性分析 - 简书 有很多人问过我这么一类问题:RabbitMQ如何确保消息可靠?很多时候,笔者的回答都是:说来话长的事情何来长话短说.的确,要确保消息可靠不只是单单几句就 ...
- RabbitMQ高级之如何保证消息可靠性?
人生终将是场单人旅途,孤独之前是迷茫,孤独过后是成长. 楔子 本篇是消息队列RabbitMQ的第四弹. RabbitMQ我已经写了三篇了,基础的收发消息和基础的概念我都已经写了,学任何东西都是这样,先 ...
- 四种途径提高RabbitMQ传输消息数据的可靠性(一)
前言 RabbitMQ虽然有对队列及消息等的一些持久化设置,但其实光光只是这一个是不能够保障数据的可靠性的,下面我们提出这样的质疑: (1)RabbitMQ生产者是不知道自己发布的消息是否已经正确达到 ...
- RabbitMQ消息可靠性分析和应用
RabbitMQ流程简介(带Exchange) RabbitMQ使用一些机制来保证可靠性,如持久化.消费确认及发布确认等. 先看以下这个图: P为生产者,X为中转站(Exchange),红色部分为消息 ...
- RabbitMQ消息可靠性分析
消息中间件的可靠性是指对消息不丢失的保障程度:而消息中间件的可用性是指无故障运行的时间百分比,通常用几个 9 来衡量.不存在绝对的可靠性只能尽量趋向完美.并且通常可靠性也意味着影响性能和付出更大的成本 ...
- RabbitMQ消息丢失问题和保证消息可靠性-消费端不丢消息和HA(二)
继续上篇文章解决RabbitMQ消息丢失问题和保证消息可靠性(一) 未完成部分,我们聊聊MQ Server端的高可用和消费端如何保证消息不丢的问题? 回归上篇的内容,我们知道消息从生产端到服务端,为了 ...
- 解决RabbitMQ消息丢失问题和保证消息可靠性(一)
原文链接(作者一个人):https://juejin.im/post/5d468591f265da03b810427e 工作中经常用到消息中间件来解决系统间的解耦问题或者高并发消峰问题,但是消息的可靠 ...
- RabbitMQ消息可靠性传输
消息的可靠性投递是使用消息中间件不可避免的问题,不管是使用kafka.rocketMQ或者rabbitMQ,那么在RabbitMQ中如何保证消息的可靠性投递呢? 先再看一下RabbitMQ消息传递的流 ...
随机推荐
- 【C语言】第4章 选择结构程序设计
第4章 选择结构程序设计 C语言有两种选择语句: if 语句,实现两个分支的选择结构 switch 语句,实现多分支的选择结构 输入3个数a,b,c,要求按由小到大的顺序输出. 可以先用伪代码写出算法 ...
- C++回调机制
一直对回调机制不是很了解,今天索性搜了很多资料顺便整理一下,进步一点点. 1.Callback方式(回调函数) 什么是回调函数? 简而言之,回调函数就是一个通过函数指针调用的函数.如果你把函数的指针( ...
- 遇到Web页面禁用鼠标右键操作时,该如何解禁?
在使用Selenium做Web UI自动化测试过程中,经常需要鼠标右击Web页面检查DOM节点,用于获取Web元素的定位信息.一般情况下,绝大多数页面都是能够响应鼠标右击操作的.但出于某些目的,有些W ...
- 前后端数据交互(四)——fetch 请求详解
fetch 是 XMLHttpRequest 的升级版,使用js脚本发出网络请求,但是与 XMLHttpRequest 不同的是,fetch 方式使用 Promise,相比 XMLHttpReques ...
- LCT 小记
全程 Link-Cut Tree,是解决动态树问题的有力科技 --题记 简单实现 LCT 的形态直观上是一堆 Splay 的合体,每个 Splay 以时间戳为关键字,各个 Splay 通过虚边相连,可 ...
- 使用dubbo-go搭建dubbo接口测试平台
背景 http接口测试只需要一个curl命令,但dubbo协议没有这样的现成接口测试工具.通常公司内的dubbo控制台或其他平台会集成一个dubbo接口测试工具. 调用一个dubbo接口,需要知道服务 ...
- tomcat服务字符编码改为UTF-8
-Dfile.encoding=UTF-8 --仅供参考
- 谈谈如何进阶Java高级工程师
从入门到瓶颈(++文末附学习脑图++) 首先,先自我介绍一下,楼主94年的,四川人,普通大专毕业. 第一阶段 实习阶段 2015年,实习阶段去浙江温州(没错,就是皮革厂的那个地方)找了份软件实施的工作 ...
- js简单化技巧
1.交换两个变量而没有第三个 let x = 1;let y = 2;[x, y] = [y, x];console.log(x, y); 输出: 2 1 2.将数字转换为字符串 const num ...
- HiveServer2的负载均衡高可用与ActicePassive高可用浅析
负载均衡的高可用 最近在工作中遇到了hiveserver2需要部署高可用的场景,去网上搜索了解过后,用了绝大多数人推荐的共同方法: Property_name Property_value Descr ...