生产者可靠性投递消息后,消费者也可能会产生一些问题,比如:没有接受到消息,接收消息后在代码执行过程中出现了异常等。在这种情况下我们需要进行额外的处理,那么就需要手动进行消息的确认签收,rabbitmq给我们提供了一个机制:ACK机制。
额外的知识:RabbitMQ的死信队列详解 - 简书 (jianshu.com)
ACK机制有三种方式:
- 自动确认 acknowledge="none"
- 手动确认 acknowledge="manual"
- 根据异常情况来确认(暂时不怎么用) acknowledge="auto"
这篇博客是在这个基础上写的(17条消息) rabbitMQ 可靠性消息投递_angen2018的博客-CSDN博客,
具体代码我会打包好了,放个链接下载。(17条消息) springcloud_rabbitMQ_消息可靠性投递.rar-Java文档类资源-CSDN下载
代码具体实现:
手动确认,在可靠性投递时使用(投递给消费者,可靠消费)
开启手动确认
spring:
rabbitmq:
port: 5672
host: localhost
username: guest
password: guest
virtual-host: /
#开启confirms这个模式
#springboot2.2.0.RELEASE支持这个
#publisher-confirm-type: correlated
publisher-confirms: true
#开启return模式
publisher-returns: true
listener:
direct:
#开启手动签收
acknowledge-mode: manual
测试:
package com.example.listener;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.Map;
@Component
@RabbitListener(queues = "queue_test6")
public class MyRabbitListener {
/**
*
* @param message 消息封装的对象,(包括了消息的序号,消息本身,消费者名称等)
* @param channel 链接的通道
* @param msg 消息本身
*/
@RabbitHandler //用于处理具体类型的消息,会自动把消息转换成对应的对象
public void receiveMessage(Message message, Channel channel,String msg){
//接收消息
System.out.println(msg);
MessageProperties messageProperties = message.getMessageProperties();
try {
//模拟业务-100
System.out.println("消费后减100元");
//模拟出问题
int i = 10/0;
//如果正常就签收消息
//参数1,消息的序号
//参数二,是否批量签收 true是批量签收
channel.basicAck(messageProperties.getDeliveryTag(),true);
} catch (Exception e) {
e.printStackTrace();
//不正常就拒收消息(丢弃了)
try {
//参数1 消息序号
//参数2 是否批量拒绝消息
//参数3 是否把消息重新回到队列中
channel.basicNack(messageProperties.getDeliveryTag(),true,false);
//不能批量处理拒绝消息。第二个参数,true会重新放回队列,所以需要自己根据业务逻辑判断什么时候使用拒绝
//channel.basicReject();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
//消费者监听队列
/*@RabbitHandler //用于处理具体类型的消息,会自动把消息转换成对应的对象
public void receiveMessage(String msg){
//接收消息
System.out.println(msg);
//模拟业务-100
}*/
//消费者监听队列
@RabbitHandler //用于处理具体类型的消息,会自动把消息转换成对应的对象
public void receiveMessage(Map msg){
//接收消息
System.out.println(msg);
//模拟业务-100
}
}
小结:
如何保证消息的高可靠性传输(数据一致)?
- 持久化:交换机持久化,队列持久化,消息持久化
- 生产方确认Confirm , Return
- 消费方确认 ACK