1、可靠抵达
为保证消息不丢失,可靠抵达,可以使用事务消息,性能下载250倍(官网说明)。为此引入确认机制
publisher confirmCallback 确认模式
在配置文件设置
spring.rabbitmq.publisher-confirms=true
1)、在创建connectionFactory的时候设置publisherConfirms(true) 选项,开启confirmcallback.
//设置确认回调
rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
/**
* 1、只要消息抵达Broker就ack=true
* @param correlationData 当前消息的唯一关联数据(这个是消息的唯一id)
* @param ack 消息是否成功收到
* @param cause 失败的原因
*/
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
System.out.println("confirm...correlationData["+correlationData+"]==>ack["+ack+"]==>cause["+cause+"]");
}
});
2)、CorrelationData:用来表示当前消息唯一性
3)、消息只要被broker接收到就会执行confirmCallback ,如果是cluster(集群)模式,需要所有broker接收到才会调用confirmCallback
4)、被broker接收到只能表示message已经到达服务器,并不能保证消息一定会被投递目标queue里。所有需要用到接下来的returnCallback.
publisher returnCallback 未投递到queue 退回模式
#开启发送端消息抵达队列的确认
spring.rabbitmq.publisher-returns=true
#只要抵达队列,以异步发送优先回调我们这个returnconfirm
spring.rabbitmq.template.mandatory=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("Fail Message["+message+"]==>replyCode["+replyCode+"]====>replyText["+replyText+"]===>exchange["+exchange+"]==>routingKey["+routingKey+"]");
}
});
1)、confirm模式只能保证消息到达broker,不能保证消息准确投递到目标queue里。在有些业务场景下,我们需要保证消息一定要投递到目标queue里,此时就需要用到return退回模式。
2)、这样如果未能投递到目标queue里将调用returnCallback,可以记录下详细到投递数据,定期的巡检或者自动纠错都需要这些数据。
consumer ack机制
(启用手动ack机制,就不会出现宕机后消息丢失)
(也可以启动拒收,然后重新放回队列,或者丢弃)
#手动ack消息
spring.rabbitmq.listener.simple.acknowledge-mode=manual
//签收货物,非批量模式
try {
if(deliveryTag%2==0){
//收货
channel.basicAck(deliveryTag,false);
System.out.println("签收了。。"+deliveryTag);
}else{
//退货 requeue=false 丢弃,requeue=true 发回服务器,服务器重新入队。
channel.basicNack(deliveryTag,false,false);
System.out.println("没有签收。。");
}
} catch (Exception e) {
//网络终端
}
1)、消费者获取到消息,成功处理,可以回复Ack给Broker
basic.ack用户肯定确认;broker将移除次消息
basic.nack用户否定确认;可以指定broker是否丢弃此消息,可以批量
basic.reject用户否定确认;同上,但不能批量
2)、默认自动ack,消息被消费者收到,就会从broker(代理服务器)的queue中移除
3)、queue无消费,消息依然会被存储,直到消费者消费
4)、消费者收到消息。默认会自动ack。如果无法确认消息是否被处理完成或者成功处理。我们可以开启手动ack模式
消息处理成,ack(),接受下一个消息,此消息broker(代理服务器)就会移除
消息处理失败,nack()/reject(),重新发送给其他人处理,或者容错后ack
消息一直没有调用ack/nack方法,broker(代理服务器)认为此消息正在被处理,不会投递给别人,此时客户端断开,消息不会被broker移除,会投递给别人