Skip to content

问:消息队列的核心作用是什么?列举几个典型应用场景。

消息队列的核心作用,总结为三个关键词:解耦、异步、削峰。

  1. 解耦:比如订单系统和库存系统,如果直接RPC调用,库存服务挂了订单就失败。用消息队列后,订单服务发个消息就走,库存服务自己慢慢消费,两边互不影响。
  2. 异步:像用户注册后发短信、邮件这些非核心操作,同步等响应太慢。丢到消息队列异步处理,用户感觉不到延迟,主流程响应更快。
  3. 削峰:大促时秒杀请求瞬间暴涨,用队列把请求缓冲住,后端按处理能力消费,避免服务被压垮。

场景:

  1. 订单创建之后,发一条预处理消息,对订单进行预处理,包括地址匹配、sku商品匹配、bom拆分等等。
  2. 订单的审核,以单号分发每一条消息,包括订单状态修改、库存扣减、优惠券核销等等。
  3. 日志采集,将日志发到消息队列,由后台程序统一处理。

问:Kafka、RabbitMQ、RocketMQ的主要区别是什么?如何根据业务需求选择?

主要区别:

  1. RabbitMQ 像个"邮政系统"——擅长灵活的路由和可靠投递,但吞吐量有限。
  2. Kafka 是"高速公路"——追求超高吞吐量,适合数据洪流,但实时性稍弱。
  3. RocketMQ 更像"高铁"——平衡吞吐和事务,尤其擅长顺序消息和分布式事务。

运维成本差挺多:

  1. RabbitMQ:运维最简单,Web控制台能看队列堆积/重发消息,但集群扩展麻烦。
  2. Kafka:扩容得分区重平衡,监控得用Exporter+Prometheus,但横向扩展能力最强。
  3. RocketMQ:运维工具最全(自带监控台),支持平滑扩容,但NameServer高可用要自己搭。

我们现在技术选型的一般习惯:

  1. 中小项目用RabbitMQ(开发运维快)
  2. 大数据量用Kafka(节省机器)
  3. 钱相关的业务必用RocketMQ(少赔钱就是赚钱)
  • OFS选用RabbitMQ,因为OFS面对的是定制化客户,RabbitMQ吞吐量已经足够,并且运维快速。
  • OMS选用RocketMQ,因为OMS是SaaS化的,运维工具全面,支持平滑扩容。

问:如何保证消息的顺序性?Kafka和RocketMQ以及RabbitMQ的实现方式有何不同?

举例:订单的地址解析成功之后,才能匹配快递。

  1. Kafka:分区锁顺序(物理隔离)。生产者用 分区键(如订单ID) 绑定消息到同一分区。消费者单线程消费同一分区(一个分区=一个顺序单元)。缺陷:分区扩容时,相同订单ID可能被路由到新分区,导致 历史消息和新消息顺序错乱。
  2. RocketMQ:队列锁+消费标记(逻辑锁)。生产者通过 MessageQueueSelector 绑定订单ID到特定队列。消费者开启 ConsumeMode.ORDERLY(顺序消费模式),对队列加锁消费。
  3. RabbitMQ:无原生支持。靠业务层实现单通道。例如结合状态标识,订单地址解析完之后才发出匹配快递的消息。

问:保证消息的顺序性情况下,如果消费者处理失败,如何避免顺序错乱?

  1. RocketMQ:可控重试。消费失败MQ在当前队列原地重试,超过重试次数后,消息转入死信队列异步修复。
  2. Kafka:旁路存储+跳过。当遇到不可修复错误, 将错误消息存入Redis或数据库,记录订单ID+错误原因,提交当前消息的offset(假装消费成功), 后台线程扫描错误消息补偿。
  3. RabbitMQ:无原生支持。业务处理。例如:消费者监听队列,失败时进行N次本地重试,彻底失败则发到死信队列。

问:死信队列

在RabbitMQ中,消息要进死信队列必须满足 三选一:

  1. 消息被拒绝(basic.reject或basic.nack)且requeue=false
  2. 消息超时过期(TTL到点)
  3. 队列满员(队列长度超限)

问:RabbitMQ如何实现延迟消息?是否使用死信队列(DLX)?

  1. 创建普通队列,设置消息过期时间 + 死信路由规则
  2. 绑定死信队列
  3. 生产者发送延迟消息
  4. 消息普通队列休眠,过期后进入死信队列被消费者处理

问:RocketMQ的延迟消息支持哪些级别?

RocketMQ用固定延迟队列避免扫描全量消息,牺牲灵活性换吞吐量。 预设了18个延迟等级,只能选固定档位:

延迟等级实际延迟时间适用场景
Level 11秒秒级重试(如支付回调)
Level 25秒短时延迟校验
Level 310秒简单缓冲
Level 430秒订单状态流转
Level 51分钟优惠券锁定释放
Level 62分钟待支付订单提醒
Level 73分钟异步操作超时
Level 84分钟临时库存预留
Level 95分钟订单未支付预释放
Level 106分钟预约类业务
Level 117分钟复杂操作延迟触发
Level 128分钟级联操作间隔
Level 139分钟多系统协同缓冲
Level 1410分钟拼团订单等待成团
Level 1520分钟物流状态跟踪
Level 1630分钟直播商品上架预告
Level 171小时订单自动确认收货
Level 182小时长周期任务(如退款审核)

问:RabbitMQ的队列阻塞如何排查?消息积压如何快速处理?是否需扩容消费者或丢弃消息?

RabbitMQ自带监控工具,可查看队列堆积情况。大部分原因如下:

  1. 内存爆仓(最常见!):查看内存状态(关键指标:memory_alarm),看是否内存超限。可以临时扩容内存,提高内存警戒线。
  2. 磁盘摆烂(暗藏杀机):查看磁盘状态,看是否空间不足,删除堆积队列(核武器!)或扩容磁盘(需运维配合)。
  3. 消费者作死(最易忽略):管理界面看到消费者在线,但 Unacked(未确认) 消息暴涨,同一连接的其他队列也被阻塞。

问:RabbitMQ架构了解情况

RabbitMQ的四大核心组件包括:

  1. 生产者(Producer):负责创建并发送消息到RabbitMQ服务器。
  2. 消费者(Consumer):从队列中获取并处理消息。
  3. 队列(Queue):存储消息,等待消费者处理。
  4. 交换机(Exchange):接收生产者发送的消息,并根据路由规则将消息转发到一个或多个队列。

问:RabbitMQ的高可用,镜像队列如何配置?

RabbitMQ 有三种模式:单机模式、普通集群模式、镜像集群模式。

单机模式

  • 特点:所有队列、交换机等组件都运行在一台服务器上。
  • 适用场景:开发或测试环境,不适合生产环境,因为不具备高可用性。

普通集群模式

  • 特点:多台服务器上部署多个 RabbitMQ 实例,队列元数据在集群中同步,但消息实体只存储在一个节点上。
  • 优点:提高了系统的可用性和吞吐量。
  • 缺点:如果存储消息的节点故障,可能导致消息丢失。
  • 适用场景:需要提高可用性,但对数据可靠性要求不高的场景。

镜像集群模式

  • 特点:队列和消息在多个节点间镜像同步,确保数据冗余和故障转移。
  • 优点:具有高可用性和数据可靠性,节点故障时不会影响消息的可用性。
  • 缺点:消息同步会增加网络带宽压力,扩展性受限。
  • 适用场景:需要同时保证高可用性和数据可靠性的场景。

在选择 RabbitMQ 的部署模式时,需要根据实际的业务需求、系统架构以及对可用性和数据可靠性的要求来决定。

问:RabbitMQ持久化

RabbitMQ通过以下方式实现持久化:

  1. 交换机持久化:在声明交换机时,将durable参数设置为true,这样交换机在RabbitMQ重启后仍能保留123。
  2. 队列持久化: 在声明队列时,将durable参数设置为true,队列及其元数据将在RabbitMQ重启后保留345。
  3. 消息持久化:发送消息时,将deliveryMode设置为2(持久化模式),消息将被存储到磁盘中,确保在RabbitMQ重启后不丢失367。

这样即使服务器重启了,它也能从硬盘上把这些“记忆”读取回来,恢复到宕机前的状态。

问:如何保证消息不丢失(可靠性)?从生产者、Broker、消费者三方面说明。

  1. 生产者:开启确认模式(Confirm Mode):生产者通过调用 channel.confirmSelect() 方法开启确认模式。在这种模式下,当生产者发送消息后,RabbitMQ会向生产者发送一个确认消息,告知生产者该消息是否成功到达服务器。
  2. 消费者: ACK确认机制 + 死信队列(DLX)。
    • ACK确认机制:消费者处理完消息后显式发送ACK,避免消息因崩溃丢失。
    • 死信队列(DLX):处理因消费者崩溃或消息超时未被确认的消息。
  3. Broker防御(防仓库丢件):加入消息持久化。

问:如何处理消息重复消费?是否依赖业务幂等性?

RabbitMQ 本身无法完全避免消息重复消费,其机制必然依赖业务层幂等性设计。

消息重复的核心根源:

  • 生产者重复发送:网络闪断导致Confirm超时,生产者重试
  • Broker重复投递:消费者ACK失败后消息重回队列(requeue=true)
  • 消费者重复处理:业务处理成功但ACK丢失(如进程崩溃)

一般业务实现方式:

  • 加入版本号控制
  • 业务状态检查

页脚:版权前显示的信息