说实话我们团队在消息队列上踩过的坑足以写一本血泪史了。最初我们用的是 RabbitMQ单机跑得好好的QPS 上了 5000 就开始报警。后来换成 Kafka以为能一劳永逸结果运维复杂度直接起飞。等我们终于把 Kafka 调稳了业务方又开始吐槽延迟太高RocketMQ 又被提上了议程。这套流程走下来我算是把三款主流消息队列的特点摸透了。今天不聊理论直接上生产数据告诉你什么场景该选什么。选型前先把场景搞清楚我见过太多团队是跟风选型——别人用 Kafka 我也用 Kafka别人换 RocketMQ 我也换。这种做法十有八九会踩坑。高吞吐量大数据场景选 Kafka 没错日均千亿级消息量 Kafka 就是为这个设计的。业务事务消息场景选 RocketMQ它原生支持事务消息和延迟消息开箱即用。中小型系统快速迭代场景RabbitMQ 反而是最优解学习成本低客户端库丰富社区活跃。听起来简单对吧但现实往往是你接手的系统三个条件都沾点边。生产环境数据对比我把这些年踩过的坑总结成一张表全部是实打实的生产数据维度KafkaRabbitMQRocketMQ单机 QPS纯队列10w3-5w5-8w端到端延迟P995-20ms1-3ms2-5ms事务消息支持需自研插件支持原生支持延迟/定时消息支持但不完善插件支持原生支持精度ms运维复杂度高中中消费模式分区消费顺序可控经典队列负载均衡广播/集群消费第一个坑Kafka 顺序问题我们有个订单系统上 Kafka 之后发现消息乱序。业务逻辑是创建订单 → 支付 → 发货。消息乱序的结果是用户还没支付就收到发货通知了。排查了三天发现问题出在 Partition 分配策略。Kafka 的分区消费是按 Partition 维度的如果你的消费者数量小于 Partition 数量部分 Partition 会被闲置但如果消费者数量大于 Partition 数量多出来的消费者就会空跑。解决方案# 查看 Topic 的 Partition 和 Consumer Group 关系bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092\--describe--grouporder-consumer-group# 输出示例# TOPIC PARTITION CURRENT-OFFSET LOG-END-OFFSET LAG CONSUMER-ID# order-events 0 1520 1580 60 consumer-1# order-events 1 1400 1450 50 consumer-2# order-events 2 - 1500 - consumer-3注意consumer-3的 LAG 是-说明这个消费者根本没分配到 Partition。解决办法是确保消费者数量不超过 Partition 数量或者把 Partition 数调大。第二个坑RabbitMQ 内存爆炸RabbitMQ 某个队列的消息突然堆积内存占用从 2GB 飙到 12GB。原因是消费者挂了但消息没被 ACKRabbitMQ 以为消费者还在处理持续堆积。排查步骤# 查看队列消息数和内存占用rabbitmqctl list_queues name messages memory durable\--formattercsv/tmp/queue_status.csv# 查看消费者的 ACK 状态rabbitmqctl list_consumers queue_name consumer_tag\ack_details prefetch_count发现问题消费者是 Python 写的某个异常没捕获进程崩了但没抛出让 RabbitMQ 感知到。消息在队列里躺了 6 个小时才被发现。避坑建议一定要设置队列最大长度x-max-length或x-max-length-bytes一定要设置消息 TTLx-message-ttl防止积压太久变质消费者必须 try-catch并在 finally 里做幂等处理# RabbitMQ 队列声明示例arguments:x-max-length:100000# 队列最大消息数x-message-ttl:86400000# 消息24小时过期x-dead-letter-exchange:dlx.exchange# 死信队列第三个坑RocketMQ 消费超时切到 RocketMQ 之后发现有时候消费者处理慢了整个消费进度卡住。原因是 RocketMQ 的长轮询机制和 Kafka 不一样——Kafka 是消费者主动拉取RocketMQ 是 Broker 推送给消费者但中间有个排队的概念。Consumer 端// 正确配置提高消费并发度PropertiespropsnewProperties();props.put(consumerThreadMin,20);// 最小消费线程props.put(consumerThreadMax,60);// 最大消费线程建议 CPU 核数的 2-3 倍props.put(pullInterval,100);// 拉取间隔msprops.put(pullBatchSize,32);// 批量拉取消息数还有一个坑是 RocketMQ 的消费顺序。Kafka 可以通过 Partition 保证单 Partition 内有序RocketMQ 的顺序消息需要单独配置// 顺序消费示例consumer.subscribe(order-topic,*);consumer.registerMessageListener((MessageListenerOrderly)(msgs,context)-{for(MessageExtmsg:msgs){// 处理订单消息processOrder(newString(msg.getBody()));}returnConsumeOrderlyStatus.SUCCESS;});注意用MessageListenerOrderly而不是MessageListenerConcurrently前者会加锁保证同一队列消息串行消费。选型决策树说了这么多给你们一个实操决策树你的场景是 ├── 日均消息量 1000万吞吐优先 │ └── 选 Kafka重要前提你能接受较高运维复杂度 │ ├── 需要事务消息订单、支付场景 │ └── 选 RocketMQ别犹豫Kafka 自研事务成本太高 │ ├── 需要延迟/定时消息订单超时关闭、任务调度 │ └── RocketMQ 延迟消息精度可达 ms 级别Kafka 要靠外部调度 │ ├── 团队小 5人快速交付优先 │ └── RabbitMQ上手快文档丰富出问题好排查 │ └── 混合场景又想高吞吐又想事务 └── RocketMQ Kafka 分层 高吞吐业务日志用 Kafka 核心交易链路用 RocketMQ写在最后消息队列选型没有银弹。不要被XX 是最牛的这种言论带偏了脱离场景谈技术选型就是在耍流氓。我们最终的架构是核心交易链路用 RocketMQ 保障事务和延迟消息海量日志采集用 Kafka 保障吞吐日常任务通知用 RabbitMQ 保障快速接入。记住一句话合适的才是最好的能解决你问题的是那个运维成本和收益平衡点上的选择。附常见错误说法纠正❌ “Kafka 是最好的消息队列什么场景都用它” → 延迟和运维复杂度了解一下❌ “RabbitMQ 性能不行早该淘汰了” → 中小场景下RabbitMQ 的易用性秒杀其他两个❌ “RocketMQ 只有阿里在用不成熟” → 阿里双十一扛过无数次验证稳定性不用怀疑