高 进阶
MQ选型对比#
一句话答案#
Kafka 高吞吐适合日志/大数据,RocketMQ 功能全适合业务消息(事务/延迟),RabbitMQ 轻量低延迟适合小规模。
核心要点
消费失败的处理策略:
1. 重试机制
第一次失败 → 等待 5s 重试
第二次失败 → 等待 30s 重试
第三次失败 → 等待 1min 重试
...
达到最大重试次数 → 投递到死信队列
(指数退避策略,避免频繁重试打爆下游)plaintext2. 死信队列(Dead Letter Queue,DLQ)
死信队列是专门存放”处理失败”消息的队列,消息进入死信队列的条件:
① 消息消费失败且超过最大重试次数
② 消息在队列中等待超过 TTL(消息过期)
③ 队列长度超过上限(消息被挤出)plaintextRocketMQ 的死信队列:
// 消费失败达到最大重试次数(默认16次)后,自动投入死信队列
// 死信 Topic 名称:%DLQ%消费者GroupID
// 监控和处理死信:
consumer.subscribe("%DLQ%MyConsumerGroup", "*");
consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> {
// 告警、人工处理、记录到 DB 等
alertService.sendAlert(msgs.get(0));
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
});javaKafka 的死信队列(需自己实现):
// Kafka 没有原生死信队列,需要自己实现:
public void consume(ConsumerRecord<String, String> record) {
int retryCount = getRetryCount(record);
try {
process(record);
} catch (Exception e) {
if (retryCount < MAX_RETRY) {
// 发到重试 Topic(延迟一定时间)
producer.send(new ProducerRecord<>("topic-retry-" + retryCount, record.value()));
} else {
// 达到最大重试,发到死信 Topic
producer.send(new ProducerRecord<>("topic-dead-letter", record.value()));
// 告警
}
}
}java处理死信的策略:
- 人工介入:告警 → 运营人员在控制台查看死信 → 手动重新处理
- 自动重试:定时任务将死信重新投递(配合幂等性)
- 降级处理:记录到数据库,由补偿任务处理
面试回答(2分钟版)
MQ 选型主要看三款:Kafka 吞吐量最高,单机百万级 TPS,基于磁盘顺序写和零拷贝,适合日志采集、大数据实时计算等高吞吐场景,但功能相对简单,没有原生延迟消息和事务消息。RocketMQ 是阿里开源的,功能最全面,原生支持事务消息、延迟消息、顺序消息、死信队列,适合电商订单、金融业务等对可靠性和功能要求高的场景,吞吐量十万级也不差。RabbitMQ 基于 Erlang 开发,轻量低延迟,路由机制灵活,适合小规模业务和消息量不大的场景,但集群扩展能力不如前两者。消费失败的处理也是面试重点:一般采用指数退避重试策略,第一次 5 秒、第二次 30 秒依次递增,超过最大重试次数后投入死信队列。RocketMQ 原生支持死信队列,Kafka 需要自己实现重试 Topic 和死信 Topic。死信消息的处理方式包括告警人工介入、定时任务自动重投、或降级记录到数据库由补偿任务处理。
追问与易错
追问方向:
- “Kafka 和 RocketMQ 怎么选?”→ Kafka 适合大数据/日志/流处理场景,吞吐极高但功能相对简单;RocketMQ 适合业务消息场景,支持事务消息、延迟消息、死信队列等丰富功能,国内电商用得多
- “RabbitMQ 适合什么场景?”→ RabbitMQ 基于 Erlang 天然高可用,支持多种路由模式(direct/topic/fanout),适合中小规模系统和需要复杂路由的场景;单机吞吐(万级)低于 Kafka(百万级)
- “公司没有运维团队怎么选 MQ?”→ 优先考虑云服务(阿里云 RocketMQ、AWS SQS/Kinesis)免运维;自建的话 RabbitMQ 部署简单文档齐全,Kafka 运维成本相对较高需要专人维护
易错点:
- ❌ 只知道概念不知道原理——面试官会追问底层实现
- ❌ 缺乏实际使用经验——结合项目场景回答更有说服力