RabbitMQ高级之消息可靠性投递
什么是可靠性投递?
生产者:作为消息发送方希望杜绝任何消息丢失或者投递失败场景。
RabbitMQ 为我们提供了两种方式用来控制消息的投递可靠性模式。
分别是:
- confirm 确认模式
- return 退回模式
消息投递路线
如下所示是生产者到消费者的模型:
RabbitMQ的整个消息投递的路径
Producer--->RabbitMQ Broker(Server)--->Exchange--->Queue--->Consumer
- 消息从 producer 到 exchange 则会返回一个 confirmCallback 。
- 消息从 exchange 到 queue 投递失败则会返回一个 returnCallback 。
我们将利用这两个 callback 控制消息的可靠性投递。
确认模式
消息从 producer 到 exchange 则会返回一个 confirmCallback ,不论消息是否成功到达exchange ,回调都会执行,只不过返回的bool类型的值是true or false的区别。
代码实现很简单,两步即可
步骤
(1)在XML配置文件中设置 ConnectionFactory 开启 publisher-confirms="true"
(2)在 rabbitTemplate 定义 ConfirmCallBack() 回调函数
代码实现
spring-rabbitmq-producer.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:rabbit="http://www.springframework.org/schema/rabbit"
- xmlns:rabb="http://www.springframework.org/schema/rabbit"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/context
- https://www.springframework.org/schema/context/spring-context.xsd
- http://www.springframework.org/schema/rabbit
- http://www.springframework.org/schema/rabbit/spring-rabbit.xsd">
-
- <!-- 1.加载配置文件-->
- <context:property-placeholder location="classpath:rabbitmq.properties"/>
-
- <!-- 2.定义rabbitmq connectionFactory -->
- <rabbit:connection-factory id="connectionFactory" host="${rabbitmq.host}"
- port="${rabbitmq.port}"
- username="${rabbitmq.username}"
- password="${rabbitmq.password}"
- virtual-host="${rabbitmq.virtual-host}"
-
- publisher-confirms="true"/>
- <!-- publisher-confirms="true" 确认模式开启!!! -->
-
- <!-- 3.定义管理交换机、队列-->
- <rabbit:admin connection-factory="connectionFactory"/>
-
- <!-- 消息的可靠性投递 -->
- <rabbit:queue id="test_queue_confirm" name="test_queue_confirm"></rabbit:queue>
- <rabbit:direct-exchange name="test_exchange_confirm">
- <rabbit:bindings>
- <rabbit:binding queue="test_queue_confirm" key="confirm"></rabbit:binding>
- </rabbit:bindings>
- </rabbit:direct-exchange>
-
- <!-- 定义rabbitTemplate对象操作可以在代码中方便发送消息-->
- <rabbit:template id="rabbitTemplate" connection-factory="connectionFactory"/>
-
- </beans>
ProducerTest
- package com.Harmony;
-
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.springframework.amqp.core.Message;
- import org.springframework.amqp.rabbit.connection.CorrelationData;
- import org.springframework.amqp.rabbit.core.RabbitTemplate;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.test.context.ContextConfiguration;
- import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
-
- @RunWith(SpringJUnit4ClassRunner.class)
- @ContextConfiguration(locations = "classpath:spring-rabbitmq-producer.xml")
- public class ProducerTest {
- /**
- * 确认模式
- * 开启:
- * 1. ConnectionFactory 中开启 publisher-confirms="true"
- * 2. 在 rabbitTemplate 定义 ConfirmCallBack() 回调函数
- */
- @Autowired
- private RabbitTemplate rabbitTemplate;
- // 2. 定义回调
-
- // 一、确认模式
- @Test
- public void testConfirm() throws InterruptedException {
- rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
- /**
- *
- * @param correlationData: 配置信息,在convertAndSend()中的重载方法有该参数
- * @param ack: 代表exchange交换机是否收到了信息,true为成功,false为失败
- * @param cause: 失败原因; 如果成功为null
- */
- @Override
- public void confirm(CorrelationData correlationData, boolean ack, String cause) {
- System.out.println(ack);
- System.out.println("confirm方法被执行了......");
- if (ack) {
- System.out.println("接收成功:" + cause);
- } else {
- System.out.println("接收失败:" + cause);
- // 以后可能会做一些处理
- }
- }
- });
- // 3. 发送消息
- rabbitTemplate.convertAndSend("test_exchange_confirm","confirm","message confirm......");
- // 由于在测试种,执行结束线程直接没有了!
- Thread.sleep(2000);
- }
-
- }
退回模式
当消息从exchange路由到 queue失败后,如果设置了rabbitTemplate.setMandatory(true)参数,则会将消息退 回给producer。并执行回调函数returnedMessage。
步骤
(1)开启回退模式 publisher-returns="true"
(2)设置ReturnCallback
(3)设置Exchange处理消息的模式:
如果消息没有路由到Queue,则会丢弃消息(默认)
如果消息没有路由到Queue,返回给消息发送方
代码实现
spring-rabbitmq-producer.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:rabbit="http://www.springframework.org/schema/rabbit"
- xmlns:rabb="http://www.springframework.org/schema/rabbit"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/context
- https://www.springframework.org/schema/context/spring-context.xsd
- http://www.springframework.org/schema/rabbit
- http://www.springframework.org/schema/rabbit/spring-rabbit.xsd">
-
- <!-- 1.加载配置文件-->
- <context:property-placeholder location="classpath:rabbitmq.properties"/>
-
- <!-- 2.定义rabbitmq connectionFactory -->
- <rabbit:connection-factory id="connectionFactory" host="${rabbitmq.host}"
- port="${rabbitmq.port}"
- username="${rabbitmq.username}"
- password="${rabbitmq.password}"
- virtual-host="${rabbitmq.virtual-host}"
-
- publisher-returns="true" />
- <!-- publisher-returns="true" 回退模式开启!!! -->
-
- <!-- 3.定义管理交换机、队列-->
- <rabbit:admin connection-factory="connectionFactory"/>
-
- <!-- 消息的可靠性投递 -->
- <rabbit:queue id="test_queue_confirm" name="test_queue_confirm"></rabbit:queue>
- <rabbit:direct-exchange name="test_exchange_confirm">
- <rabbit:bindings>
- <rabbit:binding queue="test_queue_confirm" key="confirm"></rabbit:binding>
- </rabbit:bindings>
- </rabbit:direct-exchange>
-
- <!-- 定义rabbitTemplate对象操作可以在代码中方便发送消息-->
- <rabbit:template id="rabbitTemplate" connection-factory="connectionFactory"/>
-
- </beans>
ProducerTest
- package com.Harmony;
-
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.springframework.amqp.core.Message;
- import org.springframework.amqp.rabbit.connection.CorrelationData;
- import org.springframework.amqp.rabbit.core.RabbitTemplate;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.test.context.ContextConfiguration;
- import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
-
- @RunWith(SpringJUnit4ClassRunner.class)
- @ContextConfiguration(locations = "classpath:spring-rabbitmq-producer.xml")
- public class ProducerTest {
-
- @Autowired
- private RabbitTemplate rabbitTemplate;
-
- @Test
- public void testReturn() throws InterruptedException {
- // 设置交换机处理失败消息的模式
- // 生产者可以拿到之前发送失败的消息
- rabbitTemplate.setMandatory(true);
-
- rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
- /**
- *
- * @param message: 消息对象
- * @param replyCode: 错误码
- * @param replyText: 错误信息
- * @param exchange: 交换机
- * @param routingKey: 路由键
- */
- @Override
- public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
- System.out.println("return 执行了...");
- System.out.println(message);
- System.out.println(replyCode);
- System.out.println(replyText);
- System.out.println(exchange);
- System.out.println(routingKey);
- }
- });
- // 3. 发送消息
- rabbitTemplate.convertAndSend("test_exchange_confirm","confirm","message confirm......");
- Thread.sleep(2000);
- }
-
- }
总述
➢ 设置ConnectionFactory的publisher-confirms="true" 开启确认模式。
➢ 使用rabbitTemplate.setConfirmCallback设置回调函数。当消息发送到exchange后回 调confirm方法。在方法中判断ack,如果为true,则发送成功,如果为false,则发 送失败,需要处理。
➢ 设置ConnectionFactory的publisher-returns="true" 开启退回模式。
➢ 使用rabbitTemplate.setReturnCallback设置退回函数,当消息从exchange路由到 queue失败后,如果设置了rabbitTemplate.setMandatory(true)参数,则会将消息退 回给producer。并执行回调函数returnedMessage。
➢ 在RabbitMQ中也提供了事务机制,但是性能较差,此处不做讲解。 使用channel下列方法,完成事务控制:
- txSelect(), 用于将当前channel设置成transaction模式
- txCommit(),用于提交事务
- txRollback(),用于回滚事务
I can feel you forgetting me。。 有一种默契叫做我不理你,你就不理我