消息模型详解:点对点与发布订阅
消息队列的核心,说白了就是解决「谁把消息发给谁」的问题。我做了这么多年交易系统,见过太多团队在这个基础问题上栽跟头。今天咱们就把两种消息模型掰开揉碎了讲清楚。
点对点模型(Queue)
点对点模型,也叫队列模型。它的逻辑很简单:一条消息,只能被一个消费者消费。消息进入队列后,多个消费者竞争,谁抢到算谁的。
核心特征:
- 消息一旦被消费,就从队列中移除
- 消费者之间是竞争关系
- 消息有且仅有一个消费者
我在做订单撮合系统时,就用过这种模型。订单进来后,多个撮合引擎实例都在监听同一个队列。谁空闲谁处理,天然实现了负载均衡。你想想看,如果一条订单被两个引擎同时处理,那不乱套了?
# 一个简单的点对点消息示例
import pika
# 生产者:发送订单
connection = pika.BlockingConnection(
pika.ConnectionParameters('localhost'))
channel = connection.channel()
channel.queue_declare(queue='order_queue')
channel.basic_publish(
exchange='',
routing_key='order_queue',
body='{"order_id": "20240301", "symbol": "BTC/USDT", "price": 50000}'
)
print("订单已发送")
connection.close()
# 消费者:处理订单
def callback(ch, method, properties, body):
print(f"处理订单: {body}")
# 模拟业务处理
ch.basic_ack(delivery_tag=method.delivery_tag)
channel.basic_consume(
queue='order_queue',
on_message_callback=callback,
auto_ack=False
)
channel.start_consuming()
我的经验:点对点模型最适合「任务分发」场景。比如行情数据解析、订单处理、风控检查。每个任务只需要一个worker处理,多了反而出问题。
发布订阅模型(Topic)
发布订阅模型就完全不一样了。一条消息,可以被多个消费者同时收到。生产者把消息发到「主题」上,所有订阅了这个主题的消费者都能拿到。
我记得有一次做行情推送系统,需要把实时价格同时推送给交易终端、风控系统、数据仓库。如果用点对点模型,得发三遍。用发布订阅,一次发布,多方消费,省事多了。
核心特征:
- 消息持久保留在主题中(或按策略过期)
- 消费者各自独立消费
- 一条消息可以被N个消费者处理
# 发布订阅示例
import pika
# 生产者:发布行情
connection = pika.BlockingConnection(
pika.ConnectionParameters('localhost'))
channel = connection.channel()
channel.exchange_declare(
exchange='market_data',
exchange_type='fanout' # 广播模式
)
channel.basic_publish(
exchange='market_data',
routing_key='',
body='{"symbol": "BTC/USDT", "price": 50000, "timestamp": 1709280000}'
)
print("行情已发布")
connection.close()
# 消费者A:交易终端
channel.queue_bind(
exchange='market_data',
queue='trading_terminal_queue'
)
# 消费者B:风控系统
channel.queue_bind(
exchange='market_data',
queue='risk_control_queue'
)
两者的核心区别
| 对比维度 | 点对点模型(Queue) | 发布订阅模型(Topic) |
|---|---|---|
| 消费关系 | 1对1(竞争消费) | 1对N(广播消费) |
| 消息生命周期 | 消费即删除 | 按策略保留 |
| 消费者耦合 | 强耦合(必须处理) | 弱耦合(可随时订阅/取消) |
| 典型场景 | 任务分发、负载均衡 | 事件通知、数据同步 |
| 消息顺序 | 严格有序(单队列) | 按分区有序 |
如何选择?
这个问题我经常被问到。其实没那么复杂,就两个判断标准:
- 这条消息需要被几个人处理? 一个人处理 → 点对点;多个人处理 → 发布订阅
- 消费者之间是竞争还是协作? 竞争(谁抢到谁干)→ 点对点;协作(各干各的)→ 发布订阅
我曾经踩过的坑:有次把风控事件用点对点模型发,结果两个风控实例抢着处理同一条告警,重复下了两次止损单。嗯,那次亏了不少钱。后来改成发布订阅,每个实例独立消费,再配合去重逻辑,问题才解决。
交易系统中的实战选择
我整理了一份交易系统常见场景的选型建议:
| 场景 | 推荐模型 | 原因 |
|---|---|---|
| 订单处理 | 点对点 | 每个订单只需一个引擎处理 |
| 行情推送 | 发布订阅 | 多方需要同时获取行情 |
| 风控告警 | 发布订阅 | 风控、日志、监控都要收到 |
| 交易对账 | 点对点 | 逐笔对账,顺序处理 |
| 系统日志 | 发布订阅 | 归档、分析、告警各取所需 |
一张图看懂两种模型
下面这张SVG图,把两种模型的核心逻辑画出来了。我建议你多看几遍,理解透了再动手。
我的建议:刚开始做消息队列选型时,别想太复杂。先问自己三个问题:消息给谁用?用几次?用完还要不要?答案自然就出来了。
其实两种模型没有绝对的好坏。我在同一个交易系统里,经常混用。订单处理用点对点,行情推送用发布订阅,风控告警用发布订阅但加上分区保证顺序。关键是要理解它们的本质区别,然后根据业务场景灵活选择。