一、保证消息不丢失
1、使用事务消息,性能下降250倍
2、消息确认机制
1)publisher confirmCallback 确认模式
2)publisher returnCallback 未投递到queue退回模式
3)consumer ack 机制
二、可靠抵达-ConfirmCallback
1、配置
spring.rabbitmq.publisher-confirms=true
2、说明
1)在创建connectionFactory 的时候设置PublisherConfirms(true)选项,开启confirmcallback
- CorrelationData: 用来表示当前消息唯一性
3)消息只要被broker接收到就会执行confirmCallback,如果是cluster模式,需要所有broker 接受到才会调用confirmCallback
- 被broker 接受到只能表示message 已经到达服务器,并不能保证消息一定会被投递到目标queue里。所以需要用到returnCallback
@Autworied
private RabbitTemplate rabbitTemplate;
/**
* 使用JSON 序列化机制,进行消息转换
*/
@Bean
public MessageConverter messageConverter() {
return new Jackson2JsonMessageConverter();
}
/**
* 定制RabbitTemplate
* 1、spring.rabbitmq.publisher-confirms=true
* 2、设置确认回调
*/
@PostConstruct //MyRabbitConfig 对象创建完成以后,执行这个方法
public void initRabiitTemplate() {
// 设置确认回调
rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
/**
* correlationData 当前消息的唯一关联数据(这个是消息的唯一id)
* ack 消息是否成功收到
* cause 失败的原因
*/
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
// 做一些操作
}
});
}
三、可靠抵达-ReturnCallback
1、配置
spring.rabbitmq.publisher-returns=true
spring.rabbitmq.template.mandatory=true
2、说明
1)confirm 模式只能保证消息到达broker,不能保证消息准确投递到目标queue里。有些业务场景下。我们需要保证消息一定哟啊投递到目标queue里,此时就需要用到return 退回模式
2)如果未能投递目标queue 里将调用returnCallback,可以记录下详细的投递数据,在定期的巡检或者自动纠错使用。
@PostConstruct //MyRabbitConfig 对象创建完成以后,执行这个方法
public void initRabiitTemplate() {
// 设置确认回调
rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
/**
* 只要消息没有投递给指定的队列,就触发这个失败回调
* message 投递失败的消息详细信息
* replayText 回复的状态码
* replayCode
* exchange 当这个消息发送给那个交换机
* routingKey 消息使用的那个routingKey
*/
@Override
public void returnMessage(Message message, int replayCode, String replayText, String exchange, String routingKey) {
// 做一些操作
}
});
}
四、可靠抵达-Ack消息确认机制
1、消费者获取到消息,成功处理,可以回复Ack给Broker
- basic.ack 用于肯定确认;broker 将移除此消息。
2)basic.nack用于否定确认;可以指定broker是否丢此消息,可以批量
3) basic.dreject 用于否定确认;可以指定broker是否丢此消息,不可以批量
2、默认,消息被消费者收到,就会从broker的queue 中移除
3、queue 五消费者,消息依然会被存粗。但是如果无法确定此消息是否被批处理完成,或者成功处理。我们可以开启手动ack模式
1)消息处理成功,ack(),接受下一个消息,此消息broker就会移除
2)queue 无消费者,默认会手动ack。但是如果无法确定此消息是否被处理完成,或者成功处理。可以启动手动ack模式。
a: 消息处理成功,ack,接受一下这个消息,此消息broker就会移除。
b: 消息处理失败,nack()/reject(),重新发送给其他人进行处理,或者容错处理后ack
c: 消息一直没有调用ack/nack方法,broker 认为此消息正在被处理,不会投递给别人,此时客户端断开,消息不会被broker移除,会投递给别人。
# 手动ack消息
spring.rabbitmq.listener.simple.acknowledge-model=manual
byte[] body = message.getBody();
// 消息头属性信息
MessageProperties properties = message.getMessageProperties();
// 处理消息
...
long deliverTag = message.getMessageProperties().getDeliverTag();
try {
// 接受消息
channel.basicAck()
} catch(Exception e) {
// 异常处理
}