外观
RabbitMQ 路由与分发
本页结论:消息永远先到达 Exchange,再由 Binding 决定进入哪些队列;五种 Exchange 类型的路由差异决定了竞争消费、广播与模式匹配三种分发形态。
适用场景
- 任务分发(一个队列、多个竞争消费者)。
- 事件广播(一条事件复制给多个独立订阅)。
- 按业务键路由(地区、租户、事件子类型)。
核心模型:Exchange → Binding → Queue
- 同一条消息可以进入多个队列 → 各队列的订阅者都能收到(广播)。
- 同一个队列的多个消费者 → 每条消息只给其中一个(竞争消费,Work Queue)。
- 广播与竞争消费可以同时存在:先复制到队列,再在队列内竞争。
五种 Exchange 的路由差异
| 类型 | 路由依据 | 典型用法 |
|---|---|---|
| Default(匿名,"") | routing key = 队列名,直接投递 | 本仓库 basic / retry-dlq 实验用它 |
| Direct | routing key 与 binding key 完全相等 | 按明确类别分发,如 order.created |
| Topic | routing key 按段匹配,* 一段、# 零或多段 | 层级事件路由,本仓库 routing 实验 |
| Fanout | 忽略 routing key,投给全部绑定队列 | 纯广播 |
| Headers | 按消息 headers 键值匹配(x-match=all/any) | 少用:性能差、难维护,多数场景 Topic 可替代 |
Topic 匹配要点(routing 实验验证)
| binding | 命中 order.created | 命中 order.created.eu |
|---|---|---|
order.created | 是 | 否 |
order.# | 是 | 是 |
order.created.eu | 否 | 是 |
# 可匹配零段:order.# 也能命中 order。绑定 # 的队列会收到所有消息,常用作审计/全量订阅。
动手验证:
bash
bash demos/rabbitmq/routing/run.sh三队列分别收到 2/3/1 条,与上表一致。
rabbitmq / routing
bash demos/rabbitmq/routing/run.shassert.out.txt
PASS confirmed: 3 PASS received:orders.routing.created: 2 PASS unique:orders.routing.created: 2 PASS depthAfter:orders.routing.created: 0 PASS received:orders.routing.all: 3 PASS unique:orders.routing.all: 3 PASS depthAfter:orders.routing.all: 0 PASS received:orders.routing.eu: 1 PASS unique:orders.routing.eu: 1 PASS depthAfter:orders.routing.eu: 0 RESULT: all assertions passed
consumer-all.out.txt
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. [consumer] timestamp=2026-10-07T10:26:58.311881368Z level=INFO service=order-service product=rabbitmq lab=routing messageId=01JMQ000000000000000000001 eventType=order.created schemaVersion=1 aggregateId=order-1001 traceId=00000000000000000000000000000001 correlationId=order-1001 destination=orders.routing.all consumer=consumer-1 attempt=1 redelivered=false status=received [replay-gate] timestamp=2026-10-07T10:26:58.336127392Z checkpoint=after-delivery messageId=01JMQ000000000000000000001 token=54a978db2b34-1-after-delivery-01JMQ000000000000000000001-1 status=waiting [replay-gate] timestamp=2026-10-07T10:27:00.949453933Z checkpoint=after-delivery messageId=01JMQ000000000000000000001 token=54a978db2b34-1-after-delivery-01JMQ000000000000000000001-1 status=released [consumer] timestamp=2026-10-07T10:27:00.964272955Z level=INFO service=order-service product=rabbitmq lab=routing messageId=01JMQ000000000000000000001 eventType=order.created schemaVersion=1 aggregateId=order-1001 traceId=00000000000000000000000000000001 correlationId=order-1001 destination=orders.routing.all attempt=1 status=business_committed [replay-gate] timestamp=2026-10-07T10:27:00.964897400Z checkpoint=before-ack messageId=01JMQ000000000000000000001 token=54a978db2b34-1-before-ack-01JMQ000000000000000000001-2 status=waiting [replay-gate] timestamp=2026-10-07T10:27:05.073793367Z checkpoint=before-ack messageId=01JMQ000000000000000000001 token=54a978db2b34-1-before-ack-01JMQ000000000000000000001-2 status=released [consumer] timestamp=2026-10-07T10:27:05.076470657Z level=INFO service=order-service product=rabbitmq lab=routing messageId=01JMQ000000000000000000002 eventType=order.created schemaVersion=1 aggregateId=order-1002 traceId=00000000000000000000000000000002 correlationId=order-1002 destination=orders.routing.all consumer=consumer-1 attempt=1 redelivered=false status=received [replay-gate] timestamp=2026-10-07T10:27:05.077165765Z checkpoint=after-delivery messageId=01JMQ000000000000000000002 token=54a978db2b34-1-after-delivery-01JMQ000000000000000000002-3 status=waiting [replay-gate] timestamp=2026-10-07T10:27:07.882468119Z checkpoint=after-delivery messageId=01JMQ000000000000000000002 token=54a978db2b34-1-after-delivery-01JMQ000000000000000000002-3 status=released [consumer] timestamp=2026-10-07T10:27:07.885073322Z level=INFO service=order-service product=rabbitmq lab=routing messageId=01JMQ000000000000000000002 eventType=order.created schemaVersion=1 aggregateId=order-1002 traceId=00000000000000000000000000000002 correlationId=order-1002 destination=orders.routing.all attempt=1 status=business_committed [replay-gate] timestamp=2026-10-07T10:27:07.885623129Z checkpoint=before-ack messageId=01JMQ000000000000000000002 token=54a978db2b34-1-before-ack-01JMQ000000000000000000002-4 status=waiting [replay-gate] timestamp=2026-10-07T10:27:10.489919362Z checkpoint=before-ack messageId=01JMQ000000000000000000002 token=54a978db2b34-1-before-ack-01JMQ000000000000000000002-4 status=released [consumer] timestamp=2026-10-07T10:27:10.491775880Z level=INFO service=order-service product=rabbitmq lab=routing messageId=01JMQ000000000000000000003 eventType=order.created schemaVersion=1 aggregateId=order-1003 traceId=00000000000000000000000000000003 correlationId=order-1003 destination=orders.routing.all consumer=consumer-1 attempt=1 redelivered=false status=received [replay-gate] timestamp=2026-10-07T10:27:10.492799924Z checkpoint=after-delivery messageId=01JMQ000000000000000000003 token=54a978db2b34-1-after-delivery-01JMQ000000000000000000003-5 status=waiting [replay-gate] timestamp=2026-10-07T10:27:13.197307122Z checkpoint=after-delivery messageId=01JMQ000000000000000000003 token=54a978db2b34-1-after-delivery-01JMQ000000000000000000003-5 status=released [consumer] timestamp=2026-10-07T10:27:13.199889028Z level=INFO service=order-service product=rabbitmq lab=routing messageId=01JMQ000000000000000000003 eventType=order.created schemaVersion=1 aggregateId=order-1003 traceId=00000000000000000000000000000003 correlationId=order-1003 destination=orders.routing.all attempt=1 status=business_committed [replay-gate] timestamp=2026-10-07T10:27:13.200450166Z checkpoint=before-ack messageId=01JMQ000000000000000000003 token=54a978db2b34-1-before-ack-01JMQ000000000000000000003-6 status=waiting [replay-gate] timestamp=2026-10-07T10:27:16.004987424Z checkpoint=before-ack messageId=01JMQ000000000000000000003 token=54a978db2b34-1-before-ack-01JMQ000000000000000000003-6 status=released [consumer] timestamp=2026-10-07T10:27:16.005668936Z level=INFO service=order-service product=rabbitmq lab=routing queue=orders.routing.all received=3 status=done
consumer-created.out.txt
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. [consumer] timestamp=2026-10-07T10:26:58.278084147Z level=INFO service=order-service product=rabbitmq lab=routing messageId=01JMQ000000000000000000001 eventType=order.created schemaVersion=1 aggregateId=order-1001 traceId=00000000000000000000000000000001 correlationId=order-1001 destination=orders.routing.created consumer=consumer-1 attempt=1 redelivered=false status=received [replay-gate] timestamp=2026-10-07T10:26:58.322788912Z checkpoint=after-delivery messageId=01JMQ000000000000000000001 token=8c3f770628c8-1-after-delivery-01JMQ000000000000000000001-1 status=waiting [replay-gate] timestamp=2026-10-07T10:27:02.348086193Z checkpoint=after-delivery messageId=01JMQ000000000000000000001 token=8c3f770628c8-1-after-delivery-01JMQ000000000000000000001-1 status=released [consumer] timestamp=2026-10-07T10:27:02.365020938Z level=INFO service=order-service product=rabbitmq lab=routing messageId=01JMQ000000000000000000001 eventType=order.created schemaVersion=1 aggregateId=order-1001 traceId=00000000000000000000000000000001 correlationId=order-1001 destination=orders.routing.created attempt=1 status=business_committed [replay-gate] timestamp=2026-10-07T10:27:02.365572909Z checkpoint=before-ack messageId=01JMQ000000000000000000001 token=8c3f770628c8-1-before-ack-01JMQ000000000000000000001-2 status=waiting [replay-gate] timestamp=2026-10-07T10:27:06.572907840Z checkpoint=before-ack messageId=01JMQ000000000000000000001 token=8c3f770628c8-1-before-ack-01JMQ000000000000000000001-2 status=released [consumer] timestamp=2026-10-07T10:27:06.576020145Z level=INFO service=order-service product=rabbitmq lab=routing messageId=01JMQ000000000000000000002 eventType=order.created schemaVersion=1 aggregateId=order-1002 traceId=00000000000000000000000000000002 correlationId=order-1002 destination=orders.routing.created consumer=consumer-1 attempt=1 redelivered=false status=received [replay-gate] timestamp=2026-10-07T10:27:06.576660280Z checkpoint=after-delivery messageId=01JMQ000000000000000000002 token=8c3f770628c8-1-after-delivery-01JMQ000000000000000000002-3 status=waiting [replay-gate] timestamp=2026-10-07T10:27:11.785700933Z checkpoint=after-delivery messageId=01JMQ000000000000000000002 token=8c3f770628c8-1-after-delivery-01JMQ000000000000000000002-3 status=released [consumer] timestamp=2026-10-07T10:27:11.788570771Z level=INFO service=order-service product=rabbitmq lab=routing messageId=01JMQ000000000000000000002 eventType=order.created schemaVersion=1 aggregateId=order-1002 traceId=00000000000000000000000000000002 correlationId=order-1002 destination=orders.routing.created attempt=1 status=business_committed [replay-gate] timestamp=2026-10-07T10:27:11.789163978Z checkpoint=before-ack messageId=01JMQ000000000000000000002 token=8c3f770628c8-1-before-ack-01JMQ000000000000000000002-4 status=waiting [replay-gate] timestamp=2026-10-07T10:27:14.594159796Z checkpoint=before-ack messageId=01JMQ000000000000000000002 token=8c3f770628c8-1-before-ack-01JMQ000000000000000000002-4 status=released [consumer] timestamp=2026-10-07T10:27:14.594810609Z level=INFO service=order-service product=rabbitmq lab=routing queue=orders.routing.created received=2 status=done
consumer-eu.out.txt
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. [consumer] timestamp=2026-10-07T10:26:58.422093259Z level=INFO service=order-service product=rabbitmq lab=routing messageId=01JMQ000000000000000000003 eventType=order.created schemaVersion=1 aggregateId=order-1003 traceId=00000000000000000000000000000003 correlationId=order-1003 destination=orders.routing.eu consumer=consumer-1 attempt=1 redelivered=false status=received [replay-gate] timestamp=2026-10-07T10:26:58.439351311Z checkpoint=after-delivery messageId=01JMQ000000000000000000003 token=ed799219e1f1-1-after-delivery-01JMQ000000000000000000003-1 status=waiting [replay-gate] timestamp=2026-10-07T10:27:03.654337918Z checkpoint=after-delivery messageId=01JMQ000000000000000000003 token=ed799219e1f1-1-after-delivery-01JMQ000000000000000000003-1 status=released [consumer] timestamp=2026-10-07T10:27:03.667702403Z level=INFO service=order-service product=rabbitmq lab=routing messageId=01JMQ000000000000000000003 eventType=order.created schemaVersion=1 aggregateId=order-1003 traceId=00000000000000000000000000000003 correlationId=order-1003 destination=orders.routing.eu attempt=1 status=business_committed [replay-gate] timestamp=2026-10-07T10:27:03.668731148Z checkpoint=before-ack messageId=01JMQ000000000000000000003 token=ed799219e1f1-1-before-ack-01JMQ000000000000000000003-2 status=waiting [replay-gate] timestamp=2026-10-07T10:27:09.180210952Z checkpoint=before-ack messageId=01JMQ000000000000000000003 token=ed799219e1f1-1-before-ack-01JMQ000000000000000000003-2 status=released [consumer] timestamp=2026-10-07T10:27:09.181625879Z level=INFO service=order-service product=rabbitmq lab=routing queue=orders.routing.eu received=1 status=done
producer.out.txt
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. [producer] timestamp=2026-10-07T10:26:56.798983990Z level=INFO service=order-service product=rabbitmq lab=routing messageId=01JMQ000000000000000000001 eventType=order.created schemaVersion=1 aggregateId=order-1001 traceId=00000000000000000000000000000001 correlationId=order-1001 destination=orders.events routingKey=order.created durationMs=3 status=confirmed [producer] timestamp=2026-10-07T10:26:56.803610344Z level=INFO service=order-service product=rabbitmq lab=routing messageId=01JMQ000000000000000000002 eventType=order.created schemaVersion=1 aggregateId=order-1002 traceId=00000000000000000000000000000002 correlationId=order-1002 destination=orders.events routingKey=order.created durationMs=1 status=confirmed [producer] timestamp=2026-10-07T10:26:56.805388462Z level=INFO service=order-service product=rabbitmq lab=routing messageId=01JMQ000000000000000000003 eventType=order.created schemaVersion=1 aggregateId=order-1003 traceId=00000000000000000000000000000003 correlationId=order-1003 destination=orders.events routingKey=order.created.eu durationMs=1 status=confirmed [producer] timestamp=2026-10-07T10:26:56.805523532Z level=INFO service=order-service product=rabbitmq lab=routing destination=orders.events confirmed=3 status=done
setup.out.txt
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
负载分发:Prefetch 的作用
多个竞争消费者时,RabbitMQ 默认轮询分发(round-robin)。若不设 Prefetch,Broker 可能一次把大量消息推给单个消费者,导致其他消费者空闲、该消费者积压。正确姿势:
java
channel.basicQos(1); // 未 ACK 消息最多 1 条,处理完再发下一条本仓库所有 Demo 均设置 prefetch=1,保证「慢消费者不多拿」。
常见误区
- 「Producer 直接发给队列」——除了 Default Exchange,消息都先经过 Exchange;发到未声明的 Exchange 会关 Channel。
- 「绑定可以解绑就没事了」——绑定关系本身是持久状态,声明幂等但删除绑定会改变流量走向,变更需当发布对待。
- 「routing key 就是 eventType」——本仓库约定 routing key 表达路由意图(可与 eventType 一致),队列名不应承载业务语义。
- 「Fanout + 单队列 = 广播」——广播要求每个订阅者有自己的队列;共用一个队列就退化成竞争消费。
官方资料
- Exchanges:https://www.rabbitmq.com/tutorials/amqp-concepts#exchange-direct(checkedAt: 2026-08-19)
- Tutorial 5(Topic):https://www.rabbitmq.com/tutorials/tutorial-five-java(checkedAt: 2026-08-19)
- Prefetch:https://www.rabbitmq.com/docs/consumer-prefetch(checkedAt: 2026-08-19)