消息模型详解:点对点与发布订阅

消息队列的核心,说白了就是解决「谁把消息发给谁」的问题。我做了这么多年交易系统,见过太多团队在这个基础问题上栽跟头。今天咱们就把两种消息模型掰开揉碎了讲清楚。

点对点模型(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(广播消费)
消息生命周期 消费即删除 按策略保留
消费者耦合 强耦合(必须处理) 弱耦合(可随时订阅/取消)
典型场景 任务分发、负载均衡 事件通知、数据同步
消息顺序 严格有序(单队列) 按分区有序

如何选择?

这个问题我经常被问到。其实没那么复杂,就两个判断标准:

  1. 这条消息需要被几个人处理? 一个人处理 → 点对点;多个人处理 → 发布订阅
  2. 消费者之间是竞争还是协作? 竞争(谁抢到谁干)→ 点对点;协作(各干各的)→ 发布订阅

我曾经踩过的坑:有次把风控事件用点对点模型发,结果两个风控实例抢着处理同一条告警,重复下了两次止损单。嗯,那次亏了不少钱。后来改成发布订阅,每个实例独立消费,再配合去重逻辑,问题才解决。

交易系统中的实战选择

我整理了一份交易系统常见场景的选型建议:

场景 推荐模型 原因
订单处理 点对点 每个订单只需一个引擎处理
行情推送 发布订阅 多方需要同时获取行情
风控告警 发布订阅 风控、日志、监控都要收到
交易对账 点对点 逐笔对账,顺序处理
系统日志 发布订阅 归档、分析、告警各取所需

一张图看懂两种模型

下面这张SVG图,把两种模型的核心逻辑画出来了。我建议你多看几遍,理解透了再动手。

消息模型对比 点对点模型(Queue) 生产者(Producer) 消息队列 [消息1, 消息2, 消息3...] 消费者A 消费者B 消费者C ⚡ 竞争消费,一条消息只被一个消费 发布订阅模型(Topic) 生产者(Publisher) 主题(Topic) market_data 订阅者A 订阅者B 订阅者C 📡 广播消费,每条消息所有订阅者都收到

我的建议:刚开始做消息队列选型时,别想太复杂。先问自己三个问题:消息给谁用?用几次?用完还要不要?答案自然就出来了。

其实两种模型没有绝对的好坏。我在同一个交易系统里,经常混用。订单处理用点对点,行情推送用发布订阅,风控告警用发布订阅但加上分区保证顺序。关键是要理解它们的本质区别,然后根据业务场景灵活选择。

专注资料整理