一、前言
之前我们讲,RabbitMQ server是采用轮询的方式,公平的依次给每一个消费者。下面我们就来讲讲RabbitMQ 是如何把消息持久化的。在此之前的一遍博客有一个错误(day11-RabbitMQ消息分发轮询),就是什么呐?是消费者处理消息完毕之后,需要RabbitMQ server手动去确认是否处理完毕,而不是自动确认。
1.1、RabbitMQ手动确认
说明:RabbitMQ是手动确认是否处理完毕的,而不是自动处理的。不信我们看下面的实验。
①生产者连续发两条消息到队列中,用rabbitmqctl.bat list_queues命令查看当前RabbitMQ server中的队列以及消息个数
②消费者开始消费
③这个时候再去看,shuaigaogao消息队列中的个数
还是2个消息,说明客户端那边根本就没有发确认给服务端,所以客户端(生产者)这边必须手动给服务端(生产者)一个手动确认。
手动确认需要在客户端的消息callback函数中的消息处理结束后,手动确认,确认代码如下:
ch.basic_ack(delivery_tag=method.delivery_tag)
确认方式:
这个时候消费者消费,再看看效果:
1.2、消息处理完毕,为什么需要手动确认一下呢?
因为你调用的这个callback函数之后,它可能处理完收到这个消息,它接下来要干很多事情,就是说跟这个消息没有关系了。就是函数没有处理完,但是消息已经处理完了,所以你要等到函数处理完可能要花2个消息,那服务器要等2个小时候之后才能收到,所以这个也是手动确认也会处理。
二、RabbitMQ消息持久化
队列shuaigaogao里面还为消息等着客户端(消费者)去接收,但是这个时候服务器端down机了,这个时候消息是否还在?带着这个疑问,我们来做几个实验。
2.1、重启队列和消息丢失
说明:服务端发送消息->重启RabbitMQ
①服务端传统的声明queue
channel.queue_declare(queue="shuaigaogao")
②发送3条消息
③重启RabbitMQ
总结:这个时候我的queue都没有了,都丢了,这种情况下消息都在内存里面,如果down了就down了,队列和消息都没有了
2.2、队列持久化
说明:我们把队列进行持久化,就算重启我的RabbitMQ服务,我的队列也不会丢。
队列持久化,在服务端(生产者)声明queue的时候,需如下定义:
channel.queue_declare(queue='shuaigaogao', durable=True)#durable=>持久化
①服务端发3条消息
②重启服务器
总结:这种情况的只把队列持久化了,队列自己持久化了,但是队列里面的消息还是没有了
2.3、队列和消息都持久化
说明:现在我想队列和消息都持久化,那怎么办呢。
队列和消息都持久化,在服务端(生产者)声明queue的时候,需如下定义:
channel.queue_declare(queue="shuaigaogao",durable=True) #durable=>持久化
channel.basic_publish(exchange="",
routing_key="shuaigaogao", #queue的名字
body="hello world",
properties=pika.BasicProperties(delivery_mode=2,) # make message persistent=>使消息持久化
) #body是你发送的内容
①服务端发3条消息
②重启服务器
总结:如果想队列和消息都保证持久化,就必须是声明和发消息的时候,都需要声明持久化。
③这边注意了,如果你在服务端声明持久化,在客户端也必须声明queue的时候也需要声明持久化,不然的话就会报错,声明持久化的方式和服务端一样,如图:
四、总结
- RabbitMQ在服务端没有声明队列queue持久化(durable=True)时,队列是存在内存中的,服务端down机了,队列也随之消失。
- RabbitMQ在服务端只声明queue持久化,但是在发送消息时,没有声明持久化(properties=pika.BasicProperties(delivery_mode=2,)),服务器down机,只保留队列,但是不保留消息。
- RabbitMQ在服务端声明queue持久化,并且在发消息时也声明了持久化,服务down机重启后,队列和消息都能得到保存。
- 服务端声明持久化,客户端想接受消息的话,必须也要声明queue时,也要声明持久化,不然的话,客户端执行会报错。