# 持久化

# 概念

看到了如何处理任务不丢失的情况,但是如何保障当 RabbitMQ 服务停掉以后消 息生产者发送过来的消息不丢失。

默认情况下 RabbitMQ 退出或由于某种原因崩溃时,它忽视队列 和消息,除非告知它不要这样做。

确保消息不会丢失需要做两件事:我们需要将队列和消息都标 记为持久化。

# 队列如何实现持久化

之前我们创建的队列都是非持久化的,rabbitmq 如果重启的化,该队列就会被删除掉,如果 要队列实现持久化 需要在声明队列的时候把 durable 参数设置为持久化

持久化.png

警告

如果之前声明的队列不是持久化的,需要把原先队列先删除(在可视化界面点击队列名称,进去后点击Delete),或者重新 创建一个持久化的队列,不然就会出现错误 img.png

以下为控制台中持久化与非持久化队列的 UI 显示区,这个时候即使重启 rabbitmq 队列也依然存在

持久化控制台

# 消息实现持久化

要想让消息实现持久化需要在消息生产者修改代码,MessageProperties.PERSISTENT_TEXT_PLAIN 添 加这个属性。 消息持久化

将消息标记为持久化并不能完全保证不会丢失消息。尽管它告诉 RabbitMQ 将消息保存到磁盘,但是 这里依然存在当消息刚准备存储在磁盘的时候 但是还没有存储完,消息还在缓存的一个间隔点。

此时并没 有真正写入磁盘。持久性保证并不强,但是对于我们的简单任务队列而言,这已经绰绰有余了。如果需要 更强有力的持久化策略,参考后边课件发布确认章节。

# 代码

# 生产者

import com.gao.rabbitmq.utils.RabbitMQUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.MessageProperties;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.nio.charset.StandardCharsets;

/**
 * author:      高亮
 * time:        2022/7/5
 * description: 消息应答不丢失,生产者
 */
@Slf4j
public class Producer_ACK {
    private static final String ACK_QUEUE = "ack_queue";
    public static void main(String[] args) throws IOException {
        Channel channel = RabbitMQUtils.getChannel();
        channel.queueDeclare(ACK_QUEUE,false,false,true,null);
        for (int i = 0; i < 20; i++) {
            byte[] message = ("ack message" + i).getBytes(StandardCharsets.UTF_8);
            //MessageProperties.PERSISTENT_TEXT_PLAIN 设置生产者发送消息为持久化消息(要求保存到磁盘上)保存在内存中
            channel.basicPublish("", ACK_QUEUE, MessageProperties.PERSISTENT_TEXT_PLAIN, message);
        }
        log.info("发送完毕");
    }
}