RabbitMQ 队列与消息
队列(Queue)是消息的"仓库":消息被交换机路由后最终落进队列,等消费者取走。本章讲清队列属性的语义、消息持久化的条件,以及最基本的收发流程。
队列属性与语义
声明队列时要决定四个核心属性:name、durable、exclusive、auto-delete。
| 属性 | 默认值 | 含义 |
|---|---|---|
| name | 服务端随机命名 | 队列名;同一 vhost 内唯一,重名且参数不一致会报 406 |
| durable | false | 队列声明是否持久:true 则 Broker 重启后队列仍然存在 |
| exclusive | false | 独占队列:只给声明它的那条连接用,连接关闭即自动删除 |
| auto-delete | false | 最后一个消费者取消订阅后自动删除 |
业务队列通常是 durable=true、auto-delete=false;exclusive 只适合临时用途(如 RPC 回调队列)。注意 durable 只管"队列本身",消息会不会丢要配合下文的消息持久化。
队列类型:经典、仲裁与流式
除了属性,队列还分类型。RabbitMQ 3.8 起加入仲裁队列(quorum),3.9 起加入流式队列(stream),与最初的经典队列(classic)并存:
| 类型 | 一句话特点 |
|---|---|
| 经典队列 classic | 默认类型,单副本为主,功能最全、资料最多 |
| 仲裁队列 quorum | Raft 多副本协议,数据更不容易丢,新版本推荐用于重要消息 |
| 流式队列 stream | 日志式存储、可重复消费,适合大数据量读多写多的场景 |
声明时通过 x-queue-type 参数指定,细节在第 19 章展开,入门阶段用默认经典队列即可。
消息由什么组成
每条消息 = 属性(Properties)+ 正文(Body)。是否落盘由两个条件同时决定:
消息要扛住 Broker 重启,必须同时满足:
① 队列声明 durable=true → 队列本身重启后还在
② 消息投递模式 delivery_mode=2 → 消息写入磁盘(persistent)
两条只满足一条,重启后消息都会丢
(经典队列才需要操心这两点;仲裁/流式队列天生持久化)
生产者消费者基础流程
以 Python 的 pika 为例(需先在工程内安装:pip install pika)。生产者声明持久队列并发消息:
import pika
conn = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
ch = conn.channel()
ch.queue_declare(queue='hello', durable=True) # ① 队列持久
ch.basic_publish(exchange='', routing_key='hello', # 空交换机 = 按队列名直达
body=b'Hello RabbitMQ',
properties=pika.BasicProperties(delivery_mode=2)) # ② 消息持久
print('消息已发送') # 输出:消息已发送
conn.close()
消费者监听同一队列(Java 片段写法:channel.queueDeclare + basicConsume,需放进 main 方法中运行):
import pika
conn = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
ch = conn.channel()
ch.queue_declare(queue='hello', durable=True)
def on_msg(ch, method, props, body):
print('收到:', body.decode()) # 输出:收到: Hello RabbitMQ
ch.basic_ack(delivery_tag=method.delivery_tag) # 处理完必须回 ack
ch.basic_consume(queue='hello', on_message_callback=on_msg)
ch.start_consuming() # 阻塞等待消息
消息大小限制
RabbitMQ 服务端默认不设很小的单条上限,从 4.0 起默认拒绝超过 128 MiB 的消息(可用参数调整),更早版本则默认不限制。即便如此,仍强烈建议把单条消息控制在 KB 到几 MB:消息过大既吃内存又拖慢磁盘,超大文件应先存对象存储,消息里只放文件引用。
小结
队列三问自检:durable 开了吗(重启不丢队列)、消息 delivery_mode=2 了吗(消息才落盘)、exclusive 了吗(是否临时队列)。本章示例走的"空交换机按队列名直达"只是默认交换机特例,完整路由体系从下一章交换机与绑定开始。