Skip to content

消息队列(MQ)基础与选型 ​


❓ 面试官:你们项目中为什么使用消息队列(MQ)?能举个具体的业务场景吗? ​

频率:🔥🔥🔥🔥🔥

💡 一句话总结(先抛结论): 我们在项目中使用 MQ 主要是为了解决三大痛点:异步处理(提升响应速度)、系统解耦(降低模块间依赖)、流量削峰(保护底层数据库)。

📝 详细业务场景落地:

  1. 异步处理(提速):

    • 场景:用户注册成功后,需要发送欢迎邮件和赠送新手积分。
    • 不用 MQ:注册逻辑(50ms)+ 发邮件(500ms)+ 发积分(100ms),串行执行,接口总耗时 650ms,用户疯狂转圈圈。
    • 用 MQ:核心注册逻辑执行完(50ms),向 MQ 扔一条“新用户注册”的消息,直接返回给前端“注册成功”。发邮件和发积分的服务在后台默默订阅消息去执行。接口响应时间骤降到 50ms 左右。
  2. 系统解耦(防连坐):

    • 场景:电商的订单服务。每次下单成功,需要调用库存服务扣库存、支付服务创单、物流服务发货。
    • 不用 MQ:订单服务里写满了各种 RPC 远程调用。一旦物流服务宕机或者响应极慢,整个下单主流程都会被阻塞甚至直接报错导致下单失败(这叫“连坐效应”)。
    • 用 MQ:订单服务只管自己把订单存入数据库,然后往 MQ 扔一条“下单成功”的消息就完事了。库存、物流服务谁想处理谁去订阅。哪怕物流服务挂了一天,也不影响用户正常下单(消息在 MQ 里堆积着,等它修好了慢慢消费就行)。
  3. 流量削峰(防雪崩):

    • 场景:双十一秒杀,平时 QPS 100,瞬间飙升到 10000。
    • 不用 MQ:10000 个请求直接打到底层 MySQL,数据库瞬间死锁崩溃。
    • 用 MQ:把这 10000 个秒杀请求全扔进 MQ 里排队。后端的处理程序根据自己数据库的承受能力(比如每秒最多处理 500 个),平滑地从 MQ 里拉取消息慢慢处理。用户的请求可能会觉得“正在排队中,请稍候”,但系统绝不会挂。

❓ 面试官:目前市面上主流的 MQ 有 RabbitMQ、RocketMQ 和 Kafka,你们怎么选型的? ​

频率:🔥🔥🔥🔥

💡 一句话总结(先抛结论):

  • RabbitMQ:基于 Erlang 开发,延迟极低(微秒级),自带完善的后台管理界面,中小型公司最爱。但吞吐量相对较低,且国内开发者极难定制它的源码。
  • RocketMQ:阿里开源(Java 开发),高吞吐量,经过双十一万亿级消息洗礼,极度适合业务系统。它原生地支持了高级特性(如延迟消息、事务消息、死信队列),国内大厂中大型项目首选。
  • Kafka:Scala/Java 开发,吞吐量全球第一。极致的批处理设计,但会牺牲一点点实时性。主要用于大数据领域的日志采集和实时计算流处理,极少用于普通业务链路。

📝 选型话术(你是如何说服技术总监的): "在目前的业务微服务重构中,我们最终选择了 RocketMQ。 首先,我们是纯 Java 团队,RocketMQ 出问题了我们可以直接看源码甚至修改,而 RabbitMQ 的 Erlang 我们无人能懂。 其次,我们业务中有大量诸如“下单后 30 分钟未支付自动取消”的需求,RocketMQ 原生提供了极其方便的延迟消息功能;同时在分布式事务场景下,RocketMQ 的事务消息回查机制也是业界独一档的存在。综合考量,它最符合我们的业务痛点。"


❓ 面试官:引入 MQ 后,给系统带来了哪些缺点或者风险?【中高级】 ​

频率:🔥🔥🔥

💡 一句话总结(先抛结论): 架构设计没有银弹,引入 MQ 虽然爽,但也引入了三大致命风险:系统可用性降低(MQ 挂了全完蛋)、系统复杂性急剧升高(必须处理消息丢失、重复、乱序问题)、一致性问题(分布式事务)。

📝 风险应对策略大纲: 面试官问这个问题,其实是想考察你有没有全盘的架构思维。

  1. 可用性降低:以前只管维护业务微服务,现在还得保证 MQ 不能挂。应对:必须部署 MQ 的高可用集群(如 RocketMQ 的主从 Dledger 模式,或者 Kafka 的多副本机制)。
  2. 复杂性升高(后面的核心考点):
    • 万一网络抖动,生产者消息没发出去怎么办?(消息丢失)
    • 万一消费端网络卡顿,触发重试,把一笔订单扣了两次款怎么办?(消息重复/幂等性)
    • 顺序发了状态 A 和 B,结果 B 先被消费了怎么办?(消息乱序)
  3. 一致性问题:A 系统发了消息就默认成功了,结果 B 系统消费时因为数据库死锁一直失败,导致 A 和 B 的数据处于长期的不一致状态。(需要引入补偿机制和人工预警)。