为什么项目要选择 RocketMQ?

#中间件#面试八股

为什么项目要选择 RocketMQ?

结论:选消息队列(Message Queue,MQ)比的不是峰值参数,而是"业务真正需要的能力"和"团队能承担多少维护成本"。交易类系统要事务消息、顺序消息、海量堆积削峰,RocketMQ 通常是默认答案;日志采集与流式计算选 Kafka;协议多、路由灵活、消息量不大的系统集成选 RabbitMQ。

一、三个候选的定位差异

维度RocketMQKafkaRabbitMQ
出身阿里交易链路,经双 11 验证LinkedIn 日志管道Erlang 实现的 AMQP 标准
单机吞吐十万级十万到百万级万级
延迟毫秒级毫秒级(批量大时偏高)微秒到毫秒,最低
消息模型队列 + Tag 过滤分区日志 + 消费组位点交换机 + 路由键绑定
事务消息原生支持(半消息 + 回查)仅支持流内事务,不能与本地库绑定不支持(仅发送方事务)
延迟消息4.x 固定 18 级,5.x 任意时间不支持,需自建靠 TTL + 死信队列拼装
顺序消息队列级顺序,原生 API分区内有序单队列单消费者才有序
消息回溯按时间戳重置位点按 offset / 时间戳不支持,消费即删
典型场景订单、支付、库存、削峰日志、埋点、CDC、流计算业务解耦、复杂路由、RPC 异步化

二、选型决策树

业务诉求是什么?
├─ 日志/埋点/CDC,追求吞吐,允许秒级延迟 ......... Kafka
├─ 本地事务与发消息必须一致(下单扣库存 + 发消息)
│    └─ 需要 Broker 侧回查兜底 .................. RocketMQ 事务消息
├─ 同一订单的消息必须严格按序 .................... RocketMQ 顺序消息
├─ 30 分钟未支付自动关单 ........................ RocketMQ 延迟消息
├─ 按 routing key 做多播/主题订阅,客户端语言杂 ... RabbitMQ
└─ 日消息量 < 十万、团队 2 人 ................... 先别上 MQ

最后一条常被忽略:MQ 引入的是最终一致性和幂等的复杂度。日消息量很小、也没有削峰诉求时,用一张 outbox 表加定时任务反而更省心。

三、RocketMQ 的独有能力

能力解决的问题关键机制
事务消息本地事务成功但消息发送失败半消息(Half Message)先落盘,本地事务提交后二次确认,Broker 定时回查
顺序消息同一业务键的消息乱序按业务键选队列,消费端对队列加锁,串行消费
延迟消息定时任务分散在业务代码里4.x 用 18 个延迟级别,5.x 支持任意时间戳
Tag / SQL92 过滤一个 Topic 下按业务分流Broker 侧过滤,减少无效网络传输
消息轨迹排查"消息去哪了"轨迹 Topic 记录发送、存储、消费三个节点
海量堆积大促削峰CommitLog 顺序写 + ConsumeQueue 稀疏索引,堆积只增磁盘不增随机 IO

四、落地配置示例

选定 RocketMQ 之后,生产端的可靠性配置要一起定下来:

# producer.properties
rocketmq.namesrv.addr=10.0.0.11:9876;10.0.0.12:9876
rocketmq.producer.group=order_producer
rocketmq.producer.send.timeout=3000
rocketmq.producer.retry.times=2
rocketmq.producer.compress.msg.body.over.how.much=4096
DefaultMQProducer producer = new DefaultMQProducer("order_producer");
producer.setNamesrvAddr("10.0.0.11:9876;10.0.0.12:9876");
producer.setSendMsgTimeout(3000);
producer.setRetryTimesWhenSendFailed(2);
producer.start();

// 用订单号做分区键:同一订单落到同一队列,天然获得顺序
Message msg = new Message("ORDER_TOPIC", "PAID", orderId,
        JSON.toJSONBytes(event));
SendResult r = producer.send(msg, 3000);
if (r.getSendStatus() != SendStatus.SEND_OK) {
    // 进入本地补偿表,由定时任务重投
}

选型结论要落到配置上:既然选择了支持顺序消息的 RocketMQ,就应该用订单号做分区键、用 ORDER_TOPIC 而不是"一个业务一个 Topic";既然看中可靠投递,就应该关掉"发送失败只打日志"的写法。

五、常见追问

  • RocketMQ 吞吐不如 Kafka,为什么交易系统还选它? 单机十万级对订单链路已经够用,换来的是事务消息、顺序消息、延迟消息这些 Kafka 没有的原生能力,省掉大量自研补偿代码。
  • 5.0 相比 4.x 变了什么? 引入无状态 Proxy 统一接入、POP 消费模式、任意时间延迟消息、存算分离部署,客户端协议上兼容 gRPC。
  • 能不能同时用 Kafka 和 RocketMQ? 能,但要有清晰边界:日志类走 Kafka,交易类走 RocketMQ;并在公司内部封装统一发送接口,避免业务直接耦合两套客户端。
  • 团队没人懂 Erlang,是不是就不能用 RabbitMQ? 可以,但要清楚运维成本:队列堆积、流控、集群分区处理都需要经验,出问题时排查难度不比 RocketMQ 低。

小结

  • 选型先看业务需要哪一种语义(事务、顺序、延迟、广播),再看吞吐和延迟。
  • RocketMQ 的核心卖点是把交易场景的可靠性能力做进了 Broker,而不是留给业务自研。
  • Kafka 强在吞吐与生态,RabbitMQ 强在路由灵活与低延迟,三者不是替代关系。
  • 消息量极小的系统,引入 MQ 的复杂度可能高于收益,先考虑数据库表 + 定时轮询。
笔记加载中…