1 队列持久化

RabbitMQ的队列分为两种,持久化(durable)和瞬时(transient)队列。一个节点重启后,会重新声明持久化队列。但持久化队列内的消息是否可以被恢复,取决于消息本身的持久性

队列的持久化在需要客户端声明队列时配置

现在实战一下

1.1 客户端声明队列为持久化

java的RabbitMQ客户端,channel.queueDeclare()第二个参数表示是否持久化,运行下列代码,可以看到web页面上多了一个名为durable_test的持久化队列

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

public class CreateDurableQueue {
    private final static String QUEUE_NAME = "durable_test";

    public static void main(String[] args) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("服务器IP");  // 设置服务器
        factory.setUsername("admin");  // 账号
        factory.setPassword("password");  // 密码
        try (Connection connection = factory.newConnection();  // 创建连接和通道
             Channel channel = connection.createChannel()) {
            channel.queueDeclare(QUEUE_NAME, true, false, false, null);  // 声明持久化队列
        }
    }
}

java持久化存储技术 java本地持久化队列_RabbitMQ

1.2 测试队列持久化

现在往队列durable_test中发送一条消息后重启服务器

重启前,队列中有一条未消费消息

java持久化存储技术 java本地持久化队列_持久化_02

关机后,这个队列呈现down的状态

java持久化存储技术 java本地持久化队列_持久化_03

重启后,队列中消息不存在

java持久化存储技术 java本地持久化队列_RabbitMQ_04

1.3 非持久化队列在服务器重启后

一个非持久化队列在节点重启后直接从队列列表中消失

 

2 消息持久化

持久化消息必须处在一个持久化的队列中才是有意义的。配置持久化消息的唯一方法是客户端在发送消息时配置delivery_mode为2

消息持久化并不是可靠的,因为可能在消息还没有完成持久化前服务器因为故障停机,重启节点后消息还是会丢失。

之前已经测试过,非持久化的消息在服务器重启之后不能恢复,现在来看看持久化的消息

2.1 向非持久化队列发送持久化消息

声明一个非持久化队列,发送一个持久化消息,再把服务重启

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.MessageProperties;

public class SendPersistent {
    private final static String QUEUE_NAME = "hello";

    public static void main(String[] args) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("服务器IP");  // 设置服务器
        factory.setUsername("admin");  // 账号
        factory.setPassword("password");  // 密码
        try (Connection connection = factory.newConnection();  // 创建连接和通道
        Channel channel = connection.createChannel()) {
            channel.queueDeclare(QUEUE_NAME, false, false, false, null);  // 声明非持久化队列
            String message = "Hello World";
            channel.basicPublish("", QUEUE_NAME, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());  // 创建新生产者,发送持久化文本消息
            System.out.println(" [x] Sent '" + message + "'");
        }
    }
}

重启之后,非持久化队列都木有了,何况是消息呢,皮之不存毛将焉附

2.2 向持久化队列发送持久化消息

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.MessageProperties;

public class SendPersistent {
    private final static String QUEUE_NAME = "hello";

    public static void main(String[] args) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("服务器IP");  // 设置服务器
        factory.setUsername("admin");  // 账号
        factory.setPassword("password");  // 密码
        try (Connection connection = factory.newConnection();  // 创建连接和通道
        Channel channel = connection.createChannel()) {
            channel.queueDeclare(QUEUE_NAME, true, false, false, null);  // 声明非持久化队列
            String message = "Hello World";
            channel.basicPublish("", QUEUE_NAME, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());  // 创建新生产者,发送持久化文本消息
            System.out.println(" [x] Sent '" + message + "'");
        }
    }
}

妥妥的

java持久化存储技术 java本地持久化队列_java持久化存储技术_05

2.3 镜像队列持久化消息

镜像队列的情况呢,官网文档我还没有找到相关的说明,但是我做了一个测试

在exactly镜像队列模式下,集群中有节点1、2、3,原来的master队列在2上,镜像队列在节点3,向队列发送两条持久化消息

然后首先挂掉节点2,再挂掉节点1,最后挂掉节点3

按节点2、1、3的顺序重启节点,出现的情况是,节点3成为master,节点2成为mirror,且节点2未同步,也就是说节点2的镜像队列是空的

我们可以得出一个结论,即只有master队列重启后,能恢复持久化的消息