目录
1.消息确认机制
1.1.消息确认机制介绍
这里的消息确认机制,指的是消费者对消息的确认,而不是生产者。
(1)背景缘由
当消费者把消息发送出去后,就会把消息删除。如果消费者这边处理消息成功,则相安无事;但是如果处理异常,消息也就会丢失。所以就需要设置消费者的消息确认模式
(2)消息确认的机制
消息确认机制分为两个大类:自动确认和手动确认
手动确认又分为三种模式:肯定确认、否定确认、否定批量确认
对于rabbitmq的操作有两种,我们主要介绍第二种
- 直接使用amqb提供的包(RabbitMQ Java Client库)
- 使用spring集成进来的
第一种介绍:
对于第一种主要把autoAck参数设置成false即为手动确认,改成true即为自动确认。收到确认需要调用Channel.basicAck函数
//自动确认,第二个参数为true
channel.basicConsume(Constants.RPC_RESPONSE_QUEUE,true,consumer);
//收到确认,第二个参数为false
DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String request = new String(body,"UTF-8");
System.out.println("接收到请求:"+ request);
String response = "针对request:"+ request +", 响应成功";
AMQP.BasicProperties basicProperties = new AMQP.BasicProperties().builder()
.correlationId(properties.getCorrelationId())
.build();
channel.basicPublish("", Constants.RPC_RESPONSE_QUEUE, basicProperties, response.getBytes());//返回响应
channel.basicAck(envelope.getDeliveryTag(), false);//手动确认
}
};
channel.basicConsume(Constants.RPC_REQUEST_QUEUE,false,consumer);//false
- 自动确认:当autoAck为true时,RabbitMQ会自动把发出去的消息设置为确认,然后从内存(硬盘)删除,而不会去管消费者是否真正的消费到该消息。适用对消息可靠性要求不高的场景
- 收到确认:当autoAck为false时,RabbiMQ会等待消费者显示地调用Basic.Ack命令,回复确认信号之后才会删除该消息。适用对消息可靠性要求比较高的场景
2.1.Spring-AMQP的三种消息确认(重点)
关于消息确认机制的问题:none自动确认(不管消息是否收到)、auto成功收到删除,异常收到不确认、manual手动确认
none:
(1)成功处理:不考虑
(2)消费异常:队列也会直接将消息删除
auto:
(1)成功处理--不考虑
(2)消费异常:队列不会把消息删除
- 没有进行异常捕获 --- 会一直尝试消费消息并一直报异常,队列不会把该消息删除,也就是不会确认消息
- 进行了异常捕获 --- 消费逻辑只会执行一次并,队列会删除消息
manual:手动确认模式(肯定确认和否定确认)
(1)成功处理
- 进行了肯定确认,队列将消息进行删除
- 没有进行肯定确认,队列会将消息从ready至为unacked
(2)消费异常
下面的情况是进行了异常的捕获
- 进行否定确认,但不重新入队 --- 队列会直接将消息删除
- 进行了否定确认,并且重新入队 --- 消息会重新入队,也就是队列不会将消息删除
以上是消息确认机制的情况总结。
下面展示代码:
配置文件:除了manual模式,其他模式只需要配置了就会生效
mamual模式的确认机制:
@RabbitListener(queues = Constant.ACK_QUEUE)
public void ackQueue2(Message message, Channel channel) throws IOException {
long deliveryTag = message.getMessageProperties().getDeliveryTag();
System.out.println("消息是:"+new String(message.getBody()));
System.out.println("deliveryTag下标是:"+deliveryTag);
try {
System.out.println("消费异常前");
int a=10/0;
System.out.println("消费异常后");
channel.basicAck(deliveryTag, false);
}catch (Exception e) {
System.out.println("消费异常");
channel.basicNack(deliveryTag, false, true);
}
}
下面这一段写的无需观看,都是一些学习时写的混乱思路
Spring-AMQP提供了三种消息确认机制
public enum AcknowledgeMode {
NONE ,
MANUAL ,
AUTO ;
}
- AcknowledgeMode.NONE:这种也就是对应自动确认模式。消息一旦投递给消费者,不关消费者是否成功处理,RabbitMQ都会自动确认消息,就会把消息删除。
- AcknowledgeMode.AUTO(默认):这种模式下,消费者处理成功会自动确认消息,但是如果处理失败就会抛出异常,不会确认消息。
- AcknowlegeMode.MANUAL:手动确认模式。消费者必须在成处理消息后显示的调用basicAck方法来确认消息。如果消息未被确认,RabbitMQ会认为消息尚未被成功处理,并且会重新投递消息。
(1)收到确认的两个方法
(2)先准备好下面的代码
1)常量类
public class Constant {
//消息确认机制
public static final String ACK_QUEUE = "ack_queue";
public static final String ACK_EXCHANGE = "ack_exchange";
}
2)配置类和配置文件
@Configuration
public class AckConfig {
//消息确认机制
@Bean("ackQueue")
public Queue ackQueue() {
return QueueBuilder.durable(Co