1. 簡介
在 RabbitMQ 的消息發送流程中,一共有三種消息丟失的情況:
- 生產者給 broker 發送的消息,broker 沒有收到
- broker 將消息丟失
- broker 給消費者發送消息時消息丟失
對于第一種情況,我們可以使用 RabbitMQ 提供的發布確認模式;
對于第三種情況,我們可以使用 RabbitMQ 的發布確認特性;
對于第二種情況,我們可以使用 RabbitMQ 的持久化特性。
2. 什么是持久化特性
RabbitMQ 的持久化表示的是資源存儲在硬盤中,當 RabbitMQ 服務器重啟后,設置為持久化的資源不會被釋放,除非手動刪除,不然不會丟失。
RabbitMQ 的持久化特性分為:
- 交換機持久化
- 隊列持久化
- 消息持久化
3. 交換機持久化
在 spring 中,我們聲明交換機時,可以為交換機指定是否持久化。
聲明持久化交換機:
//寫法一 @Bean("persExchange")public DirectExchange persExchange() {return ExchangeBuilder.directExchange(Constants.PRES_EXCHANGE).build();}//寫法二@Bean("persExchange")public DirectExchange persExchange() {return ExchangeBuilder.directExchange(Constants.PRES_EXCHANGE).durable(true).build();}
在寫法一中,沒有指定 durable 參數,那么默認就會聲明一個持久化交換機。
聲明非持久化交換機:
@Bean("notPersExchange")public DirectExchange notPersExchange() {return ExchangeBuilder.directExchange(Constants.NOT_PERS_EXCHANGE).durable(false).build();}
將 durable 參數設置為 false,就會聲明一個非持久化交換機。
4. 隊列持久化
我們也可以為隊列指定是否持久化。
聲明持久化隊列:
@Bean("persQueue")public Queue persQueue() {return QueueBuilder.durable(Constants.PERS_QUEUE).build();}
調用 durable 方法即可聲明一個持久化隊列。
聲明非持久化隊列:
@Bean("notPersQueue")public Queue notPersQueue() {return QueueBuilder.nonDurable(Constants.NOT_PERS_QUEUE).build();}
調用 nonDurable 方法即可聲明一個持久化隊列。
5. 消息持久化
生產者在發送消息時,可以指定該消息是否持久化。
發送持久化消息:
@RequestMapping("/pres")public String pers() {String messageInfo = "pres message";Message message = new Message(messageInfo.getBytes(StandardCharsets.UTF_8),new MessageProperties());//設置消息持久化message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);rabbitTemplate.convertAndSend(Constants.PRES_EXCHANGE, Constants.PERS_ROUTINGKEY, message);return "持久化消息發送成功";}
MessageDeliveryMode 提供了兩個參數,分別為?PERSISTENT 和 NON_PERSISTENT,表示持久化和非持久化。
發送非持久化消息:
@RequestMapping("/nPres")public String nPers() {String messageInfo = "nPres message";Message message = new Message(messageInfo.getBytes(StandardCharsets.UTF_8),new MessageProperties());//設置消息非持久化message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.NON_PERSISTENT);rabbitTemplate.convertAndSend(Constants.NOT_PERS_EXCHANGE, Constants.PERS_ROUTINGKEY, message);return "非持久化消息發送成功";}
6. 交換機、隊列、消息三者之間持久化的影響
- 當交換機為持久化時,重啟服務器,交換機依然存在
- 當交換機為非持久化時,重啟服務器,交換機不存在
- 當隊列為持久化、隊列中的消息為持久化時,重啟服務器,隊列依然存在,隊列中的消息依然存在
- 當隊列為持久化、隊列中的消息為非持久化時,重啟服務器,隊列依然存在,隊列中的消息不存在
- 當隊列為非持久化、隊列中的消息為持久化時,重啟服務器,隊列不存在,隊列中的消息不存在
- 當隊列為非持久化、隊列中的消息為非持久化時,重啟服務器,隊列不存在,隊列中的消息不存在