Appearance
消息中间件全景:选型、能力与落地
消息中间件(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 只发布事件,下游各自订阅 |
| 削峰填谷 | 高峰流量直接打爆数据库或第三方接口 | 消息先进入队列,消费者按能力处理 |
| 异步任务 | 用户请求等待慢操作完成 | 请求快速返回,后台异步执行 |
| 广播通知 | 逐个调用订阅方 | 多消费者订阅同一事件 |
| 事件回放 | 历史事件丢失,无法重建状态 | 保留消息后可重新消费 |
| 最终一致性 | 分布式事务复杂 | 通过事件、重试、幂等、补偿实现 |
主流组件能力地图
| 组件 | 核心模型 | 最强能力 | 典型场景 | 选型关键词 |
|---|---|---|---|---|
| RabbitMQ | Exchange + Queue | 灵活路由、任务队列、协议生态 | 业务异步、任务分发、微服务解耦 | 好上手、路由强 |
| Kafka | Topic + Partition Log | 高吞吐、可回放、流处理生态 | 日志、埋点、CDC、实时数据管道 | 事件流、数据平台 |
| RocketMQ | Topic + Queue | 事务消息、顺序消息、延时消息 | 订单、支付、库存、交易链路 | 业务语义强 |
| Pulsar | Topic + 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 件事
- 消息契约:字段、版本、兼容策略、事件命名。
- Topic/Queue 规划:按业务域拆分,不要所有消息共用一个主题。
- 消息键设计:用于分区、顺序、幂等和排查。
- 投递语义:至少一次、至多一次,还是需要事务协同。
- 幂等策略:唯一键、防重表、状态机、乐观锁。
- 失败策略:重试次数、退避间隔、死信、人工补偿。
- 消息生命周期:TTL、保留时间、归档、清理。
- 监控告警:堆积、延迟、失败率、重试量、死信量。
统一案例:订单超时关闭 + 支付成功发券
这套案例会在每篇组件文档里展开:
mermaid
flowchart LR
Order[订单服务] -->|order.created| MQ[(MQ)]
Payment[支付服务] -->|order.paid| MQ
MQ --> Timeout[超时检查消费者]
MQ --> Coupon[发券消费者]
Timeout --> OrderDB[(订单库)]
Coupon --> CouponDB[(券库)]核心业务规则:
- 下单 30 分钟未支付,自动关闭订单。
- 支付成功后异步发券。
- 超时关闭和支付成功存在竞态,订单状态机必须兜底。
- 发券必须幂等,不能重复发。
不同组件实现方式:
| 组件 | 推荐实现 |
|---|---|
| RabbitMQ | TTL + DLX 实现延时检查,失败进入重试/死信 |
| Kafka | 事件流 + 调度服务,适合可回放和审计 |
| RocketMQ | 延时消息 + 事务消息,最贴近交易业务语义 |
| Pulsar | Delayed 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
