mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
1588 words
4 minutes
MQ 从 0 到 1(二):RabbitMQ 基础模型
2025-08-17

MQ 从 0 到 1(二):RabbitMQ 基础模型#

上一篇讲了为什么需要 MQ。

这一篇开始看 RabbitMQ。

RabbitMQ 是一个很常见的消息队列中间件,它的核心模型可以先记成一句话:

生产者不直接把消息发给队列,而是先发给交换机,交换机根据规则把消息路由到队列,消费者再从队列里消费。

这句话很重要。

很多初学者以为 RabbitMQ 是:

Producer -> Queue -> Consumer

但更准确的是:

Producer -> Exchange -> Queue -> Consumer

RabbitMQ 里的几个角色#

先看核心概念。

概念作用
Producer生产者,负责发送消息
Exchange交换机,负责路由消息
Queue队列,负责存放消息
Binding绑定关系,把交换机和队列关联起来
Routing Key路由键,生产者发送消息时携带
Consumer消费者,负责处理消息
BrokerRabbitMQ 服务本身

可以用快递系统类比:

Producer:寄件人
Exchange:分拣中心
Queue:派送站点
Consumer:快递员
Routing Key:地址信息
Binding:分拣规则

生产者把包裹交给分拣中心。

分拣中心根据地址和规则,把包裹送到不同站点。

快递员从站点拿包裹去派送。

为什么要有 Exchange#

如果生产者直接发队列,会有一个问题:

生产者必须知道消息要发到哪个队列。

这会让生产者和队列强绑定。

RabbitMQ 加了一层 Exchange,让生产者只关心业务事件。

比如订单创建后:

订单服务发送消息到 order.exchange
routingKey = order.created

至于这条消息最终进哪个队列,由交换机和绑定规则决定。

order.exchange
+ order.created -> sms.queue
+ order.created -> point.queue
+ order.created -> search.queue

这样新增一个消费者,只需要新增队列和绑定关系,不需要改生产者逻辑。

Direct Exchange#

direct 是最直观的交换机。

它按照 routing key 精确匹配。

Exchange: order.direct
Binding:
sms.queue <绑定> order.created
refund.queue <绑定> order.refunded

发送消息时:

routingKey = order.created

消息会进入:

sms.queue

如果发送:

routingKey = order.refunded

消息会进入:

refund.queue

适合场景:

  • 根据明确业务动作分发;
  • 一个 routing key 对应一个或多个队列;
  • 比如订单创建、订单取消、退款成功。

Fanout Exchange#

fanout 不看 routing key。

它会把消息广播给所有绑定到这个交换机的队列。

Exchange: order.fanout
Binding:
sms.queue
point.queue
search.queue
analysis.queue

生产者发送一条订单创建消息。

所有绑定队列都会收到。

order.fanout
-> sms.queue
-> point.queue
-> search.queue
-> analysis.queue

适合场景:

  • 一个事件需要多个系统都知道;
  • 生产者不关心具体有哪些消费者;
  • 比如订单创建广播、配置刷新广播。

Topic Exchange#

topic 支持通配符匹配,是业务里非常常用的交换机。

常见规则:

* 匹配一个单词
# 匹配零个或多个单词

比如 routing key 设计成:

order.created
order.paid
order.cancelled
refund.created
refund.success

绑定规则:

order.* 匹配 order.created、order.paid、order.cancelled
order.# 匹配所有 order 开头的多级事件
*.created 匹配 order.created、refund.created

适合场景:

  • 消息类型比较多;
  • 希望按业务模块或事件类型灵活订阅;
  • 比如 order.*user.*coupon.*

三种交换机怎么选#

交换机特点适合场景
directrouting key 精确匹配明确路由
fanout广播给所有绑定队列事件广播
topic通配符匹配复杂业务事件订阅

如果刚开始做业务系统,我更建议优先用 topic

因为它比 direct 灵活,又不像 fanout 那样完全广播。

比如:

order.created
order.paid
order.cancelled
order.refunded

后面想订阅全部订单事件,可以绑定:

order.#

只想订阅订单创建,可以绑定:

order.created

Queue 是消息真正存放的地方#

Exchange 不负责长期保存消息。

消息最终要进入 Queue。

消费者是从 Queue 中取消息。

所以,队列设计也很重要。

一个常见做法是:

业务模块 + 消费目的 + queue

比如:

order.sms.queue
order.point.queue
order.search.queue
order.analysis.queue

不要所有业务共用一个大队列。

否则会出现几个问题:

  • 消费逻辑混在一起;
  • 一个消费者慢会影响其他业务;
  • 失败重试不好区分;
  • 监控和排查都不清晰。

更推荐按消费目的拆队列。

Binding 是路由规则#

Binding 可以理解成交换机和队列之间的路由规则。

比如:

Exchange: order.topic
Queue: order.sms.queue
Binding Key: order.created

意思是:

当消息发送到 order.topic,并且 routing key 匹配 order.created 时,把消息投递到 order.sms.queue

如果有多个队列绑定同一个 routing key,那么多个队列都会收到消息。

这就是一条消息驱动多个消费者的基础。

Consumer 消费消息#

消费者监听队列。

order.sms.queue -> SmsConsumer
order.point.queue -> PointConsumer
order.search.queue -> SearchConsumer

每个消费者只处理自己的业务。

例如短信消费者只关心发短信:

public void handle(OrderCreatedMessage message) {
smsService.sendOrderCreatedMessage(message.getOrderId());
}

积分消费者只关心加积分:

public void handle(OrderCreatedMessage message) {
pointService.addOrderPoint(message.getOrderId());
}

这样业务边界会清楚很多。

消息确认 Ack#

消费者收到消息后,RabbitMQ 需要知道这条消息是否已经处理成功。

这就涉及 Ack。

常见模式有两种:

模式说明
自动确认消息投递给消费者后就认为成功
手动确认消费者处理成功后主动确认

真实业务里,更推荐手动确认。

因为自动确认有风险:

RabbitMQ 把消息发给消费者
消费者刚收到,业务还没处理
应用宕机
RabbitMQ 已经认为消息成功
消息丢失

手动确认的思路是:

收到消息
执行业务
业务成功
发送 ack

如果业务失败,可以重试、拒绝或进入死信队列。

可靠消费会在后面的文章单独讲。

持久化#

RabbitMQ 里要注意三个持久化:

  • Exchange 持久化;
  • Queue 持久化;
  • Message 持久化。

只持久化队列还不够,消息本身也要设置为持久化。

可以粗略理解成:

Exchange 和 Queue 持久化:RabbitMQ 重启后结构还在。
Message 持久化:RabbitMQ 重启后消息尽量不丢。

为什么说“尽量”?

因为消息可靠性还和生产者确认、磁盘刷盘、集群配置有关。不能只靠一个 durable 就以为万无一失。

一个订单消息模型#

下面是一个适合入门项目的设计。

Exchange:
order.topic.exchange
Routing Key:
order.created
order.paid
order.cancelled
Queues:
order.sms.queue 绑定 order.created
order.point.queue 绑定 order.paid
order.search.queue 绑定 order.#
order.analysis.queue 绑定 order.#

效果:

订单创建:
order.created -> 短信、搜索、分析
订单支付:
order.paid -> 积分、搜索、分析
订单取消:
order.cancelled -> 搜索、分析

这种设计比所有消息塞进一个队列更清晰。

小结#

这一篇先把 RabbitMQ 的基础模型记住:

  • 生产者把消息发给 Exchange;
  • Exchange 根据 Binding 和 Routing Key 把消息路由到 Queue;
  • Consumer 从 Queue 消费消息;
  • direct 适合精确路由;
  • fanout 适合广播;
  • topic 适合灵活订阅;
  • 业务队列建议按消费目的拆分;
  • 真实项目要关注 ack 和持久化。

上一篇:MQ 从 0 到 1(一):为什么需要消息队列

下一篇:MQ 从 0 到 1(三):Spring Boot 集成 RabbitMQ

Share

If this article helped you, please share it with others!

MQ 从 0 到 1(二):RabbitMQ 基础模型
https://mizuki.mysqil.com/posts/message-queue-02-rabbitmq-basics/
Author
梦幻晨风
Published at
2025-08-17
License
CC BY-NC-SA 4.0

Some information may be outdated

Table of Contents