消息队列面试场景问答¶
一、如何保证消息不被重复消费?¶
MQ 通常保证 At least once,可能重复。解决:消费端幂等。
常见做法:
- 唯一业务 ID:消息带
bizId,消费前查 Redis: - 数据库唯一索引:插入重复主键会失败。
- 状态机:订单只有
INIT -> PAID才能推进,重复消息直接忽略。
二、如何保证消息不丢失?¶
三段保障:
- 生产端:同步发送 + 重试,确认 Broker 收到。
- Broker:持久化到磁盘 + 主从复制。
- 消费端:业务处理完再 ACK,不要先 ACK 再处理。
反例
消费者收到消息立刻 ACK,然后业务处理时宕机,这条消息就丢了。
三、如何保证消息顺序?¶
- 同一业务 key(如 orderId)hash 到同一 Queue。
- 单 Queue 单线程消费。
- RocketMQ 用
MessageQueueSelector:
注意:局部顺序可以做到,全局顺序代价极大(单 Queue 串行),一般不做。
四、消息积压怎么办?¶
- 先看是生产太快还是消费太慢。
- 消费慢:临时扩容消费者实例数(注意不能超过 Queue 数)。
- 批量消费、异步处理。
- 实在处理不过来,先转储到新 Topic,慢慢消费。
- 紧急情况:丢弃非核心消息,保住主流程。
五、延迟消息怎么实现?¶
- RocketMQ:内置 18 个延迟级别(1s、5s、10s...2h)。
- Kafka:没有原生支持,用时间轮 / 外部调度。
- RabbitMQ:TTL + DLX。
六、MQ 如何选型?¶
| Kafka | RocketMQ | RabbitMQ | |
|---|---|---|---|
| 吞吐量 | 极高(百万级) | 高(十万级) | 中(万级) |
| 延迟 | ms 级 | ms 级 | us 级 |
| 顺序 | Partition 内顺序 | Queue 内顺序 | Queue 内顺序 |
| 延迟消息 | 不支持原生 | 支持 | TTL+DLX |
| 事务消息 | 支持(弱) | 支持 | 不支持 |
| 适用 | 大数据、日志 | 电商、业务 | 中小规模、路由复杂 |
七、为什么用 MQ?¶
- 异步:下单后发短信、积分,主流程不等待。
- 削峰:秒杀流量先入 MQ,消费者按能力消费。
- 解耦:系统间不直接调用,通过 MQ 通信。
一句话总结
MQ 不是银弹,引入它就要接受:异步带来的复杂性、重复消费、消息丢失、顺序、积压这些问题。