正常情況下,如果消息經過交換器進入隊列就可以完成消息的持久化,但如果消息在沒有到達broker之前出現意外,那就造成消息丟失,有沒有辦法可以解決這個問題?
RabbitMQ有兩種方式來解決這個問題:
一、通過AMQP提供的事務機制實現;
二、使用發送者確認模式實現
如下爲使用發送發確認來保證隊列到達隊列
1、開啓發送發確認,及開啓消息手動確認
2、初始化隊列:
3、發送方確認回調
public class RabbitConfirmCallback implements RabbitTemplate.ConfirmCallback,RabbitTemplate.ReturnCallback {
private Logger logger= LoggerFactory.getLogger(RabbitConfirmCallback.class);
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
if (ack) {
logger.info("消息已確認 cause:{} - {}",correlationData);
} else {
logger.info("消息未確認 cause:{} - {}",correlationData);
}
}
@Override
public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
logger.info("消息被退回 {}" , message.toString());
}
}
4、生產者
@Controller
@RequestMapping("translationEx")
public class transProducer{
private Logger logger= LoggerFactory.getLogger(transProducer.class);
@Autowired
private RabbitTemplate rabbitTemplate;
@PostConstruct
public void initRabbitTemplate() {
// 設置生產者消息確認
rabbitTemplate.setConfirmCallback(new RabbitConfirmCallback());
rabbitTemplate.setReturnCallback(new RabbitConfirmCallback());
}
@RequestMapping("/sendMessage")
public void send() {
//發送字符串
for(int i=0;i<10;i++){
//該隨機數會到達發送方確認的回調方法,用來判斷消息是否已經達到隊列
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
this.rabbitTemplate.convertAndSend(null,"pConfirm", "a"+i,correlationData);
}
}
}
5、消費者
@Component
public class TransCustomer {
private Logger logger= LoggerFactory.getLogger(TransCustomer.class);
@RabbitListener(queues="pConfirm")
public void processA(String msg,Channel channel,Message message) throws IOException {
logger.info("ReceiveMessage:"+msg);
try {
//告訴服務器收到這條消息 已經被我消費了 可以在隊列刪掉 這樣以後就不會再發了 否則消息服務器以爲這條消息沒處理掉 後續還會再發
channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
System.out.println("receiver success");
} catch (IOException e) {
e.printStackTrace();
//丟棄這條消息
//channel.basicNack(message.getMessageProperties().getDeliveryTag(), false,false);
//ack返回false,並重新回到隊列
//channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
System.out.println("receiver fail");
}
}
}
6、測試