消息可靠投递
在使用RabbitMQ的时候,作为消息发送方希望杜绝任何消息丢失或者投递失败场景。RabbitMQ为我们提供了两种方式用来控制消息的投递可靠性模式。
- confirm 确认模式
- return 退回模式
rabbitmq整个消息投递的路径为:
producer—>rabbitmq broker—> exchange—>queue—>consumer
- 消息从producer 到exchange则会返回一个confirmCallback 。
- ·消息从exchange–>queue投递失败则会返回一个returnCallback .
我们将利用这两个callback 控制消息的可靠性投递
确认步骤:
- 确认模式开启:ConnectionFactory中开启publisher-confirms=“true”
- 在rabbitTemplate定义confirmcalLBack回调函数
//2. 定义回调
rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
/**
*
* @param correlationData 相关配置信息
* @param ack exchange交换机 是否成功收到了消息。true 成功,false代表失败
* @param cause 失败原因
*/
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
System.out.println("confirm方法被执行了....");
if (ack) {
//接收成功
System.out.println("接收成功消息" + cause);
} else {
//接收失败
System.out.println("接收失败消息" + cause);
//做一些处理,让消息再次发送。
}
}
});
//3. 发送消息
rabbitTemplate.convertAndSend("test_exchange_confirm111", "confirm", "message confirm....");
}
回退步骤:
当消息发送给Exchange后,Exchange路由到Queue失败是 才会执行 ReturnCallBack
- 开启回退模式:publisher-returns=“true”
- 设置ReturnCallBack
- 设置Exchange处理消息的模式:
- 如果消息没有路由到Queue,则丢弃消息(默认)
- 如果消息没有路由到Queue,返回给消息发送方ReturnCallBack
//设置交换机处理失败消息的模式
rabbitTemplate.setMandatory(true);
//2.设置ReturnCallBack
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....");
Consumer Ack
ack指Acknowledge,确认。表示消费端收到消息后的确认方式。
有三种确认方式:
- 自动确认: acknowledge=“none”(只接收正常的消息)
- 手动确认:acknowledge=“manual”
- 根据异常情况确认: acknowledge=“auto”,(这种方式使用麻烦)
其中自动确认是指,当消息一旦被Consumer接收到,则自动确认收到,并将相应message 从RabbitMQ的消息缓存中移除。但是在实际业务处理中,很可能消恩接收到,业务处理现出现异常,那么该消息就会丢失。如果设置了手动确认方式,则需要在业务处理成功后,调用channel.basicAck(),手动签收,如果出现异常,则调用channel.basickNack()方法,让其自动重新发送消息。
设置手动签收步骤:
-
设置手动签收。acknowledge=“manual”
<!--定义监听器容器--> <rabbit:listener-container connection-factory="connectionFactory" acknowledge="manual" prefetch="1" >
-
让监听器类实现ChannelAwareMessageListener接口
@Component public class AckListener implements ChannelAwareMessageListener { @Override public void onMessage(Message message, Channel channel) throws Exception { } }
-
如果消息成功处理,则调用channel的 basicAck()签收。如果消息处理失败,则调用channel的basicNack()拒绝签收,broker重新发送给consumer
long deliveryTag = message.getMessageProperties().getDeliveryTag(); try { //1.接收转换消息 System.out.println(new String(message.getBody())); //2. 处理业务逻辑 System.out.println("处理业务逻辑..."); int i = 3/0;//出现错误 //3. 手动签收 channel.basicAck(deliveryTag,true); } catch (Exception e) { //e.printStackTrace(); //4.拒绝签收 /* 第三个参数:requeue:重回队列。如果设置为true,则消息重新回到queue,broker会重新发送该消息给消费端 */ channel.basicNack(deliveryTag,true,true); //channel.basicReject(deliveryTag,true); }