RabbitMQ支持消息的持久化,也就是数据写在磁盘上,为了数据安全考虑,我想大多数用户都会选择持久化。消息队列持久化包括3个部分:
1、exchange持久化,在声明时指定durable => 1
2、queue持久化,在声明时指定durable => 1
3、消息持久化,在投递时指定delivery_mode => 2(1是非持久化)或者设置MessageProperties.PERSISTENT_TEXT_PLAIN
如果exchange和queue都是持久化的,那么它们之间的binding也是持久化的。如果exchange和queue两者之间有一个持久化,一个非持久化,就不允许建立绑定。
Java实现
factory.setUsername("guest");
factory.setPassword("guest");
factory.setHost("127.0.0.1");
factory.setVirtualHost("/");
factory.setPort(5672);
/**
* 创建连接
*/
Connection connection = factory.newConnection();
/**
* 创建信道
*/
Channel channel = connection.createChannel();
/**
* 声明一个type=topic持久化的 非自动删除的交换器
* 第三个参数表示是否持久化
*/
channel.exchangeDeclare(EXCHANGE_NAME, "direct", true, false, null);
/**
* 声明一个持久化 非排他的 非自动删除的队列,第二个参数表示是否持久化
*/
channel.queueDeclare(QUEUR_NAME, true, false, false, null);
/**
* 将交换器与队列通过路由键绑定
*/
bindingKey = "#." + bindingKey + ".#";
channel.queueBind(queueName, EXCHANGE_NAME, bindingKey);
/**
* 发送一条持 久化消息
* MessageProperties.PERSISTENT_TEXT_PLAIN表示
*/
String message="Hello RabbitMq!";
channel.basicPublish(EXCHANGE_NAME, ROUTING_KEY, MessageProperties.PERSISTENT_TEXT_PLAIN , message.getBytes());
/**
* 关闭资源
*/
channel.close();
connection.close();
其中关于方法的定义
1、queueDeclare
Queue.DeclareOk queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete,Map<String, Object> arguments) throws IOException;
参数释义如下
- queue:队列名称
- durable: 是不持久化, true ,表示持久化,会存盘,服务器重启仍然存在,false,非持久化
- exclusive : 是否排他的,true,排他。如果一个队列声明为排他队列,该队列公对首次声明它的连接可见,并在连接断开时自动删除
- autoDelete::是否自动删除,true,自动删除,自动删除的前提:至少有一个消息者连接到这个队列,之后所有与这个队列连接的消息都断开时,才会自动删除,备注:生产者客户端创建这个队列,或者没有消息者客户端连接这个队列时,不会自动删除这个队列
2、exchangeDeclare
Exchange.DeclareOk exchangeDeclare(String exchange,
String type,
boolean durable,
boolean autoDelete,
boolean internal,
Map<String, Object> arguments) throws IOExcept
参数释义
- exchange :交换器的名称
- type : 交换器的类型,常见的有direct,fanout,topic等
- durable :设置是否持久化。durable设置为true时表示持久化,反之非持久化.持久化可以将交换器存入磁盘,在服务器重启的时候不会丢失相关信息。
- autoDelete:设置是否自动删除。autoDelete设置为true时,则表示自动删除。自动删除的前提是至少有一个队列或者交换器与这个交换器绑定,之后,所有与这个交换器绑定的队列或者交换器都与此解绑。不能错误的理解—当与此交换器连接的客户端都断开连接时,RabbitMq会自动删除本交换器
- internal:设置是否内置的。如果设置为true,则表示是内置的交换器,客户端程序无法直接发送消息到这个交换器中,只能通过交换器路由到交换器这种方式。
Python声明实现
logger.info('Declaring exchange %s', exchange_name)
# 声明exchange,durable表示是否持久化
self._channel.exchange_declare(callback = self.on_exchange_declareok,
exchange = exchange_name,
exchange_type = ’topic‘,
durable = True,
auto_delete = False,
passive = False)
# 声明队列,durable表示是否持久化
logger.info('Declaring queue %s', queue_name)
self._channel.queue_declare(callback = self.on_queue_declareok,
queue = queue_name,
durable = True,
auto_delete = False,
passive = False)
# 绑定key、exchange、queue
logger.info('Binding %s to %s with %s',exchange_name, queue_name, ROUTING_KEY)
self._channel.queue_bind(self.on_bindok,queue_name,exchange_name, ROUTING_KEY)
# 发送消息
logger.info('Published message # %s', message)
self._channel.basic_publish(exchange_name, routing_key, message,properties=pika.BasicProperties(delivery_mode=2, ) )
持久化的后遗症
比如说你初始化了一个队列msgs.你会发现它真的持久了!每次服务器端重启后,通过list_queues命令查看的时候都存在.但是时间久了,这个msgs我们并不需要了,想清除这个队列只能删除它所在的vhost,然后再重建vhost,再设置vhost的权限.
rabbitmqctl delete_vhost /
rabbitmqctl add_vhost /
rabbitmqctl set_permissions -p / rainbird ‘.’ '.’ ‘.*’
要注意,如果这个操作过程中有接收端处于连接状态它们不会自动断开,但也不会再收到消息,需要手动重新连接一下.