← 返回思维链目录

消息队列思维链

从"为什么用 MQ、消息丢了/重复了/积压了"出发,顺藤摸瓜找到根因

1. 为什么用 MQ:三大作用

起点下单要扣库存+发短信+加积分,同步调用太慢
本质:MQ 是生产者和消费者之间的缓冲区。三大作用:异步(不用等)、解耦(不直接依赖)、削峰(挡住流量洪峰)。引入 MQ = 引入" eventual consistency"和"消息可靠性的复杂度"。
🌊 顺藤摸瓜
① 异步
下单 → 扣库存(必须同步)→ 发短信/加积分丢 MQ 异步处理 → 用户不用等 → 响应快
异步处理不用等下游
② 解耦
订单服务不直接调短信/积分服务 → 通过 MQ 通知 → 新增"发优惠券"功能只要新订阅消息,订单服务不用改
解耦新增订阅不改生产者
③ 削峰
秒杀瞬间 10 万请求 → MQ 挡住 → 消费者按自己的速度慢慢处理 → 保护下游不被打挂
削峰填谷保护下游
④ 代价
引入复杂度:① 消息可靠性(丢了怎么办);② 幂等(重复了怎么办);③ 顺序(乱序怎么办);④ 积压(消费跟不上);⑤ 运维复杂(MQ 本身要高可用)
消息丢失重复消费顺序问题
关键认知:MQ 不是"快",而是"解耦+缓冲"。引入它 = 用复杂度换灵活性。不是所有场景都该用 MQ,同步能解决就别加。

2. RabbitMQ vs Kafka vs RocketMQ

本质:不同 MQ 设计目标不同 —— RabbitMQ 重可靠/灵活路由,Kafka 重高吞吐/日志流,RocketMQ 兼顾可靠+顺序+事务。
MQ擅长吞吐延迟选型场景
RabbitMQ可靠、路由灵活、延迟低万级微秒业务消息、订单、通知
Kafka高吞吐、日志流、持久化百万级毫秒日志、大数据、流计算
RocketMQ顺序、事务消息、可靠十万级毫秒金融、电商(阿里)
选型:业务消息/低延迟用 RabbitMQ;日志/大数据/高吞吐用 Kafka;要顺序/事务/金融用 RocketMQ。别什么都上 Kafka(运维重)。

3. 消息丢了怎么办

现象用户下单了,但没发短信(消息丢了)
本质:消息从生产到消费经过三个环节,每个环节都可能丢:生产者→MQ→消费者。要保证可靠,三个环节都要防丢。
🌊 顺藤摸瓜(三个环节)
① 生产端丢
发消息时网络断了/生产者挂了 → 确认机制(publisher confirm)→ 发之前先存本地消息表 → 确认成功才删 → 失败重发
生产确认本地消息表
② MQ 丢
MQ 自己挂了消息没了 → 持久化(消息写磁盘)→ 队列持久化 + 消息持久化 + 集群/镜像
消息持久化队列持久化镜像队列
③ 消费端丢
消费者拿到消息还没处理完就 ACK 了,然后挂了 → 手动 ACK(处理完再确认)→ 别用自动 ACK
手动 ACK处理完再确认

4. 重复消费:为什么短信发了两条

现象用户收到两条同样的短信
本质:MQ 保证的是至少一次投递(At Least Once) —— 网络超时/重试会导致重复。消费端必须幂等(处理多次结果一致)。
🌊 顺藤摸瓜
① 为什么重复
消费者处理完,ACK 还没发就挂了 → MQ 认为没处理 → 重投递 → 消费者又处理一遍 → 重复
② 怎么幂等
唯一 ID + 去重表(处理前查有没有处理过);② Redis 标记(setnx);③ 数据库唯一约束(重复插入报错);④ 状态机(已处理的拒绝再处理)
唯一 ID 去重Redis 标记唯一约束状态机

5. 消息顺序:增删改不能乱

现象先删后建的消息,被消费成先建后删,数据没了
本质:多消费者并行处理时,消息可能乱序。保证顺序 = 同 key 进同 partition/队列,单线程消费
🌊 顺藤摸瓜
① 为什么乱序
多个消费者并行 → 消息被分散处理 → 执行顺序乱了 → 同一订单的"创建→支付→退款"可能乱
② 怎么保证
同 key 进同 partition(Kafka)→ 单线程消费这个 partition → 同一业务的消息有序 → 代价:并行度降低
同 key 同 partition单线程消费局部有序

总结

问题本质方案
为什么用 MQ异步/解耦/削峰但引入可靠性/幂等/顺序复杂度
消息丢了三个环节都可能丢生产确认+MQ持久化+手动ACK
重复消费At Least Once 重试消费端幂等(去重表/Redis/唯一约束)
顺序乱了多消费者并行同 key 同 partition,单线程消费
选哪个 MQ各有擅长RabbitMQ(业务)/Kafka(日志)/RocketMQ(事务)
本质:MQ 是"用可靠性复杂度换解耦和缓冲"。用之前想清楚:丢消息能接受吗?重复怎么处理?顺序重要吗?不是所有场景都该上 MQ。