Skip to content

消息中间件全景:选型、能力与落地

消息中间件(MQ)不是简单的“队列工具”,它解决的是分布式系统里的异步解耦、削峰填谷、事件分发、可靠投递、状态同步和流式处理问题。

一套业务系统从单体走向微服务或事件驱动时,最先遇到的通常不是“怎么发一条消息”,而是:

  • 下游系统慢了,主链路要不要等?
  • 多个系统都关心一个业务事件,谁来通知?
  • 失败要重试几次?重复消费怎么办?
  • 消息要保留多久?能不能回放?
  • 是否需要顺序、事务、延时、广播、多租户?

这篇是总览页,重点回答“为什么需要 MQ、怎么选、落地时要设计什么”。具体组件能力见:

MQ 在系统中的位置

mermaid
flowchart LR
  User[用户请求] --> API[业务服务]
  API --> DB[(业务数据库)]
  API --> MQ[(消息中间件)]
  MQ --> Worker[异步任务服务]
  MQ --> Notify[通知服务]
  MQ --> Search[搜索索引]
  MQ --> BI[实时数仓/报表]

  Worker --> Ext[第三方系统]
  Notify --> SMS[短信/邮件/站内信]

核心变化是:主链路只完成必要的业务提交,耗时或可异步的动作交给 MQ 后面的消费者处理。

MQ 解决的典型问题

问题不用 MQ 的表现使用 MQ 后
应用解耦A 服务直接调用 B/C/D,任一下游失败影响主链路A 只发布事件,下游各自订阅
削峰填谷高峰流量直接打爆数据库或第三方接口消息先进入队列,消费者按能力处理
异步任务用户请求等待慢操作完成请求快速返回,后台异步执行
广播通知逐个调用订阅方多消费者订阅同一事件
事件回放历史事件丢失,无法重建状态保留消息后可重新消费
最终一致性分布式事务复杂通过事件、重试、幂等、补偿实现

主流组件能力地图

组件核心模型最强能力典型场景选型关键词
RabbitMQExchange + Queue灵活路由、任务队列、协议生态业务异步、任务分发、微服务解耦好上手、路由强
KafkaTopic + Partition Log高吞吐、可回放、流处理生态日志、埋点、CDC、实时数据管道事件流、数据平台
RocketMQTopic + Queue事务消息、顺序消息、延时消息订单、支付、库存、交易链路业务语义强
PulsarTopic + Subscription + BookKeeper多租户、存算分离、多订阅模型云原生统一消息平台、跨地域平台化、多租户

选型流程图

mermaid
flowchart TD
  Start[需要消息中间件] --> Q1{主要是业务异步任务?}
  Q1 -- 是 --> Q2{需要复杂路由/协议兼容?}
  Q2 -- 是 --> Rabbit[RabbitMQ]
  Q2 -- 否 --> Simple{需要事务/顺序/延时强语义?}
  Simple -- 是 --> Rocket[RocketMQ]
  Simple -- 否 --> Rabbit

  Q1 -- 否 --> Q3{主要是高吞吐事件流/日志/埋点?}
  Q3 -- 是 --> Kafka[Kafka]
  Q3 -- 否 --> Q4{需要多租户平台化/跨地域/存算分离?}
  Q4 -- 是 --> Pulsar[Pulsar]
  Q4 -- 否 --> Q5{核心交易链路?}
  Q5 -- 是 --> Rocket
  Q5 -- 否 --> Kafka

消息投递的基本语义

语义含义风险落地建议
至多一次最多投递一次可能丢消息只适合日志、指标等可丢场景
至少一次至少成功投递一次可能重复最常见,消费者必须幂等
精确一次业务结果看起来只发生一次实现复杂依赖事务、幂等、状态机组合

现实工程里不要幻想“MQ 帮我保证业务绝对只执行一次”。更可靠的做法是:MQ 至少一次 + 消费者幂等 + 业务状态机约束

一个标准消息处理链路

mermaid
sequenceDiagram
  participant P as Producer
  participant M as MQ Broker
  participant C as Consumer
  participant D as Database
  participant DLQ as Dead Letter Queue

  P->>M: 发送消息
  M-->>P: broker 确认
  M->>C: 投递消息
  C->>D: 执行业务处理
  alt 处理成功
    C-->>M: ack / commit offset
  else 可重试失败
    C-->>M: nack / 不提交
    M->>C: 延迟后重投
  else 超过重试上限
    M->>DLQ: 投递死信
  end

落地前必须设计的 8 件事

  1. 消息契约:字段、版本、兼容策略、事件命名。
  2. Topic/Queue 规划:按业务域拆分,不要所有消息共用一个主题。
  3. 消息键设计:用于分区、顺序、幂等和排查。
  4. 投递语义:至少一次、至多一次,还是需要事务协同。
  5. 幂等策略:唯一键、防重表、状态机、乐观锁。
  6. 失败策略:重试次数、退避间隔、死信、人工补偿。
  7. 消息生命周期:TTL、保留时间、归档、清理。
  8. 监控告警:堆积、延迟、失败率、重试量、死信量。

统一案例:订单超时关闭 + 支付成功发券

这套案例会在每篇组件文档里展开:

mermaid
flowchart LR
  Order[订单服务] -->|order.created| MQ[(MQ)]
  Payment[支付服务] -->|order.paid| MQ
  MQ --> Timeout[超时检查消费者]
  MQ --> Coupon[发券消费者]
  Timeout --> OrderDB[(订单库)]
  Coupon --> CouponDB[(券库)]

核心业务规则:

  • 下单 30 分钟未支付,自动关闭订单。
  • 支付成功后异步发券。
  • 超时关闭和支付成功存在竞态,订单状态机必须兜底。
  • 发券必须幂等,不能重复发。

不同组件实现方式:

组件推荐实现
RabbitMQTTL + DLX 实现延时检查,失败进入重试/死信
Kafka事件流 + 调度服务,适合可回放和审计
RocketMQ延时消息 + 事务消息,最贴近交易业务语义
PulsarDelayed Delivery + Key_Shared,同订单保序并行消费

参考链接整理

  • RabbitMQ:官方 Tutorials、Publisher Confirms、Consumer Acknowledgements、Quorum Queues、Streams、Federation
  • Kafka:官方 Documentation、Design、Producer Configs、Exactly Once Semantics、Transactions
  • RocketMQ:官方 Message、Normal/FIFO/Delay/Transaction Message、Consumer Group、Retry Policy
  • Pulsar:官方 Architecture、Messaging、Schema、Tiered Storage、Geo-Replication、Functions、Connectors
别急,先让缓存热一下。