代码编织梦想

1、简介

      持久化可以提高 RabbitMQ 的可靠性, 以防在异常情况(重启、关闭、宕机等)下的数据丢失 。RabbitMQ的持久化分为三个部分:交换器的持久化、队列的持久化和消息的持久化 。

2、交换器持久化

      交换器的持久化是通过在声明交换器时将 durable 参数置为 true 实现的,如果交换器不设置持久化,那么在 RabbitMQ 服务重启之后,相关的交换器元数据会丢失,不过消息不会丢失,只是不能将消息发送到这个交换器中了。对一个长期使用的交换器来说,建议将其置为持久化的。下面展示交换器的定义方法,使用exchangeDeclare来进行定义,exchangeDeclare 有多个重载方法,这些重载方法都是由下面这个方法中缺省的某些参数

      这个方法的返回值是Exchange.DeclareOK , 用来标识成功声明了一个交换器。
      各个参数详细说明如下所述。
—exchange : 交换器的名称。
—type : 交换器的类型,常见的如 fanout、 direct 、topic 
—durable: 设置是否持久化 。 durable设置为true表示持久化, 反之是非持久化 。持久化可以将交换器存盘,在服务器重启的时候不会丢失相关信息。
—autoDelete : 设置是否自动删除。 autoDelete设置为true则表示自动删除。自动删除的前提是至少有一个队列或者交换器与这个交换器绑定,之后所有与这个交换器绑定的队列或者交换器都与此解绑。注意不能错误地把这个参数理解为 : "当与此交换器连接的客户端都断开时, RabbitMQ会自动删除本交换器 "。
—internal : 设置是否是内置的。如果设置为true ,则表示是内置的交换器,客户端程序无法直接发送消息到这个交换器中,只能通过交换器路由到交换器这种方式。
—argument : 其他一些结构化参数,比如 alternate-exchange  

      交换器的持久化是在声明交换器时,将durable参数设置为true实现的。交换器不设置持久化对消息的可靠性来说没有什么影响,但是当broker服务重启之后,exchange将不复存在,发送方producer就无法正常发送消息。相关的交换器元数据将会丢失,不过消息不会丢失,只是不能将消息发送到这个交换器中了,建议将交换器设置为持久化。

3、队列持久化

      队列的持久化是通过声明队列时,durable参数设置为true实现的。如果队列不设置持久化,那么rabbitmq服务重启之后,相关的队列元数据将会丢失,而消息是存储在队列中的,所以队列中的消息也会丢失。队列使用queueDeclare方法来定义,相对于exchangeDeclare方法而言,重载方法的个数就少很多 , 它只有两个重载方法:

(1) Queue . DeclareOk queueDec1are() throws IOException;
(2) Queue. DeclareOk queueDeclare (String queue , boolean durable , boolean exclusive, boolean autoDelete, Map<String , Object> arguments) throws IOException;
      不带任何参数的 queueDeclare 方法默认创建一个由 RabbitMQ 命名的(类似这种amq.gen-LhQzlgv3GhDOv8PIDabOXA 名称,这种队列也称之为匿名队列〉、排他的、自动删除的、非持久化的队列。
      方法的参数详细说明如下所述:

—queue : 队列的名称。
—durable: 设置是否持久化。为 true 则设置队列为持久化。持久化的队列会存盘,在服务器重启的时候可以保证不丢失相关信息。
—exclusive : 设置是否排他。为 true 则设置队列为排他的。如果一个队列被声明为排他队列,该队列仅对首次声明它的连接可见,并在连接断开时自动删除。这里需要注意三点:排他队列是基于连接( Connection) 可见的,同一个连接的不同信道 (Channel)
是可以同时访问同一连接创建的排他队列; "首次"是指如果一个连接己经声明了 一个排他队列,其他连接是不允许建立同名的排他队列的,这个与普通队列不同:即使该队列是持久化的,一旦连接关闭或者客户端退出,该排他队列都会被自动删除,这种队列
适用于一个客户端同时发送和读取消息的应用场景。
—autoDelete: 设置是否自动删除。为 true 则设置队列为自动删除。自动删除的前提是:至少有一个消费者连接到这个队列,之后所有与这个队列连接的消费者都断开时,才会自动删除。不能把这个参数错误地理解为: "当连接到此队列的所有客户端断开时,这个队列自动删除",因为生产者客户端创建这个队列,或者没有消费者客户端与这个队
列连接时,都不会自动删除这个队列。
—argurnents: 设置队列的其他一些参数,如 x-rnessage-ttl 、 x-expires 、x -rnax-length 、 x-rnax-length-bytes 、 x-dead-letter-exchange 、 x-deadletter-routing-key, x-rnax-priority 等。

例如:

Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare("queue.persistent.name", true, false, false, null);
关键的是第二个参数设置为true,即durable=true。

 

4、消息持久化

       队列的持久化能保证其本身的元数据不会因异常情况而丢失,但是并不能保证内部所存储的消息不会丢失。要确保消息不会丢失, 需要将其设置为持久化。通过将消息的投递模式(BasicProperties中的deliveryMode 属性)设置为2即可实现消息的持久化。MessageProperties.PERSISTENT TEXT PLAIN实际上是封装了这个属性 


设置了队列和消息的持久化,当 RabbitMQ 服务重启之后,消息依旧存在。单单只设置队列持久化,重启之后消息会丢失;单单只设置消息的持久化,重启之后队列消失,继而消息也丢失。单单设置消息持久化而不设置队列的持久化显得毫无意义。 

      发送消息的详细内容:

如果要发送一个消息,可以使用 Channel 类的 basicPublish 方法,比如发送一条 内容为 "Hello World! "的消息,参考如下:

byte[] messageBodyBytes = "Hello , world! ". getBytes();
channel.basicPublish(exchangeName , routingKey , null , messageBodyBytes);

为了更好地控制发送,可以使用 mandatory 这个参数 , 或者可以发送一些特定属性的信息 :
channe1.basicPub1ish(exchangeName,routingKey,mandatory,MessageProperties.PERSISTENT TEXT PLAIN,
messageBodyBytes) ;
上面这行代码发送了一条消息,这条消息的投递模式 (deliverymode) 设直为 2 ,即消息会被持久化(即存入磁盘)在服务器中。同时这条消息的优先级 ( priority)设置为 1 , contentype为" text/plain" 。 可以自己设定消息的属性:

对于 basicPublish而言 ,有几个重载方法 :

(1) void basicPublish (String exchange , String routingKey, BasicProperties props ,byte[) body) throws IOException ;
(2) void basicPub1ish(String exchange , String routingKey, boo1ean mandatory,BasicProperties props , byte[] body) throws IOException;
(3) void basicPublish(Stri 口 g exchange, String routingKey, boolean mandatory,boolean immediate , BasicProperties props , byte[] body) throws IOException ;

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接: https://blog.csdn.net/wangqsse/article/details/107353676