MQTT、EMQX、RabbitMQ、RocketMQ、Kafka一网打尽:消息中间件选型指南
你有没有遇到过这种情况:项目里要用消息中间件,打开搜索引擎一看,MQTT、EMQX、RabbitMQ、RocketMQ、Kafka 五个词铺天盖地,每个看着都像是“消息队列”,但细看又不知道到底该选哪个。跟同事讨论的时候,有人坚持说 MQTT 是物联网标配,有人说 Kafka 才是大数据的王,还有人甩给你一句“RabbitMQ 够用了”,结果项目排期都过了两天,方案还没定下来。
这里头最大的坑,其实不是“选哪个”,而是大家根本没意识到:这五个词根本不是一个物种。有人是协议,有人是协议的具体实现,有人是通用的消息队列,有人是分布式流平台。把它们放在同一个筐里比较,本身就是思路混了。我这些年做 IoT 平台、做数据中台、做订单系统,这几个中间件轮着用了个遍,也踩了不少坑,今天干脆把这五个东西掰开揉碎讲清楚,它们各自是什么、解决什么问题、怎么选型,一次说明白。
1. 先分清地基和房子:MQTT与EMQX的真实关系
1.1 MQTT 到底是个啥:它是“语言”不是“工具”
很多人第一次接触 MQTT,是被 ESP8266、STM32 或者 4G 模块带进来的,搞着搞着就开始问“MQTT 跟 Kafka 哪个好”,这就是典型的把协议和中间件混为一谈。
MQTT 的全称是 Message Queuing Telemetry Transport,直译就是“消息队列遥测传输”。它本质上是一套应用层通信协议,规定了消息的发布、订阅、主题、服务质量这几个核心机制,跟客户端用什么语言、跑在什么系统上没关系。你可以把它理解成“普通话”或者“英语”这种语言本身,而 EMQX、Mosquitto 这些则是“说这门语言的服务器程序”。
为什么 IoT 设备普遍认准 MQTT?因为它被设计出来的场景是窄带宽、高延迟、网络不稳定的嵌入式环境。协议头非常小(固定头部只占 2 字节,对比 HTTP 那动辄几百字节的头部),支持三种 QoS 等级来控制消息可靠性和传输开销的平衡,还有遗嘱消息这种专门处理设备掉线的机制。对于跑在电池供电、内存可能只有几百 KB 的 MCU 上的设备来说,这是最务实的选择。
1.2 EMQX 是 MQTT 协议的“服务器实现”
EMQX 是 Erlang/OTP 写的 MQTT Broker,也就是 MQTT 协议的服务端实现。客户端通过 MQTT 协议连接到 EMQX,发布消息、订阅主题,由 EMQX 来做消息的路由和转发。
EMQX 的核心优势体现在两个地方:高并发连接和集群扩展。Erlang 天生就是为电信级高并发场景设计的,单台 EMQX 节点可以撑住百万级别的连接数,这对设备接入场景极其关键——一个中型的 IoT 平台可能同时在线几十万台设备,用 Java 系的应用服务器硬扛 TCP 长连接很容易被线程数拖垮,但 EMQX 这种事件驱动架构,每个连接的开销要小得多。
这个定位决定了 EMQX 对应的是“设备与云端之间的管道”,它关注的是连接管理、消息路由、权限认证(比如通过 MySQL、Redis 做客户端认证)、数据桥接(把消息转发到 Kafka、数据库、Webhook)。如果你只是解决“服务器之间传消息”的问题,EMQX 并不是最合适的选择。
1.3 MQTT 生态里的其他角色
跟 EMQX 同类的 MQTT Broker 还有 Mosquitto(轻量级,适合嵌入式网关)、HiveMQ(商业支持好)、EMQX 的开源版(功能完整度高)。客户端工具常用的有 MQTT X,这个是我平时调试设备消息用得最多的工具,支持多主题订阅、消息模拟发送,还可以直接查看协议层面的 QoS 设置。
另外常见的问题是“EMQX 和 RabbitMQ 都支持 MQTT,怎么选”。这里有个关键区别:RabbitMQ 对 MQTT 的支持是通过插件实现的,它的核心协议是 AMQP;EMQX 则是从内核层面就是为 MQTT 打造的。如果场景是纯粹的 IoT 设备接入,我建议用 EMQX,无论从协议支持深度、连接数、还是后续扩展钩子(Webhook、数据桥接)来说都更顺手。RabbitMQ 的 MQTT 插件更适合偶尔接收几个设备消息、但主体还是企业应用消息路由的场景。
2. RabbitMQ:通用消息队列的“路由器”
2.1 核心模型:交换机、队列、绑定
RabbitMQ 最初基于 AMQP(Advanced Message Queuing Protocol)协议,设计哲学是“灵活路由”。它有三个核心概念:交换机(Exchange)、队列(Queue)、绑定(Binding)。
你可以这么理解:生产者把消息发给交换机,交换机按照路由规则把消息投递到对应的队列,消费者从队列里取消息。交换机和队列之间通过 Binding 建立关系。交换机有四种类型:Direct(精确匹配路由键)、Topic(通配符匹配)、Fanout(广播给所有队列)、Headers(按消息头匹配)。这个模型让 RabbitMQ 在“复杂路由”场景下非常灵活,比如一个订单消息可以根据路由键同时进入订单处理队列、审计队列和短信通知队列。
2.2 RabbitMQ 解决什么问题,以及在 Spring Boot 里的用法
RabbitMQ 特别适合企业级应用集成场景:订单系统、支付回调、邮件短信发送、日志收集等。它的特点是功能完备、管理界面好用、社区资料庞大,几乎你能想到的典型消息场景,RabbitMQ 都有成熟的方案。
在 Spring Boot 里用 RabbitMQ,核心是配置队列、交换机、绑定关系。简单给个示例:
生产者发送消息:
消费者监听:
这种模式把业务系统之间的耦合彻底打散:订单服务只需要把消息发到交换机,至于谁消费、怎么消费,订单服务完全不关心。
2.3 上手实操:Docker Compose 部署与常见坑
要用 RabbitMQ 做开发,我建议直接用 Docker Compose 起一个带管理界面的实例:
启动命令:
启动后访问 http://localhost:15672 就能打开管理界面,默认账号 admin / admin123。
我见过不少人在 Windows 上直接安装 RabbitMQ 然后启动失败,原因五花八门,但最常见的就那么几个:Erlang 和 RabbitMQ 版本不匹配;安装路径有中文;端口 5672 被占用;缺少运行库。如果你是在 Windows 本地学习,我更推荐直接用 Docker;如果环境不允许用 Docker,那就务必先确认 Erlang 版本和 RabbitMQ 版本兼容,这一点官方文档有对照表,安装前先查一下,能省一半的排查时间。
2.4 RabbitMQ 适合谁学、适合什么场景
RabbitMQ 的学习曲线在消息队列里算平缓的。它的 Web 管理界面很直观,队列积压、消费者数量、消息速率都一目了然,很适合用来入门消息队列的整体概念。选型上,如果你做的是企业内部系统、业务量还没到千万级消息每天的规模,RabbitMQ 往往是性价比最高的选择。但要注意它的吞吐量上限,没有分区的概念,单队列的吞吐一般在每秒万级到十万级,跟后面要说的 Kafka 和 RocketMQ 不是一个量级。
3. RocketMQ:站在电商场景里打磨出来的“狠角色”
3.1 RocketMQ 从哪里来,为什么说是电商基因
RocketMQ 是阿里巴巴开源的消息中间件,最后捐给了 Apache 基金会。它的诞生背景是双十一这种极端场景:订单量瞬间峰值高到离谱,消息不仅要发得快,还要保证严格有序、不丢消息。所以 RocketMQ 的设计里有很多电商特有的考虑:事务消息、延迟消息、消费位点精准管理。
RocketMQ 的领域模型比 RabbitMQ 简单清晰一些:Producer 发消息,Consumer 收消息,Broker 存储和转发。消息按主题(Topic)管理,每个主题可以有多个队列(Message Queue),队列是 RocketMQ 做并发和顺序控制的基本单位。消费可以分成集群消费(一条消息只被一个消费者处理)和广播消费(所有消费者都处理)。
3.2 核心机制:事务消息与延迟消息
事务消息是 RocketMQ 的杀手锏。电商下单有个经典难题:扣库存和创建订单这两个操作必须一致,但它们是两个独立服务。RocketMQ 的事务消息能解决“本地事务和消息发送的原子性”问题,流程是:先发半消息(Half Message)到 Broker,然后执行本地事务(扣库存),最后 Commit 或 Rollback 这个消息。Broker 会主动回查事务状态,保证消息发送和业务事务最终一致。
延迟消息也是电商高频需求:比如下单后 30 分钟未付款自动关单、支付超时提醒。RocketMQ 支持延迟级别,代码里写几行就能实现定时效果:
延迟级别对应关系(默认配置,可自定义):1s、5s、10s、30s、1m、2m、3m、4m、5m、6m、7m、8m、9m、10m、20m、30m、1h、2h。级别 4 就是 30 秒,这个在设计定时关单时必须弄清楚,否则测试的时候发现消息五分钟才到,排查半天发现自己把级别弄错了。
3.3 单机部署与 mqadmin 运维要点
RocketMQ 分 NameServer 和 Broker 两个角色,NameServer 负责路由发现,Broker 负责存储转发。单机部署时先启动 NameServer,再启动 Broker:
Topic 创建时有两个选项值得注意:-r 指定读写队列数,默认是 4 个读队列、4 个写队列。如果你预期某个主题的消费吞吐量需要提升,可以把读队列调大一些。-b 是 Broker 地址,-c 是集群名称,单机部署用 -b 直接用 Broker 地址就行。
我个人在 Windows 上部署 RocketMQ 4.8.0 的体会是,它在 Windows 下需要修改启动脚本的内存配置,因为默认的 -Xms4g -Xmx4g 对于开发机来说太高了。修改 bin/runserver.cmd 和 bin/runbroker.cmd 里的 JVM 参数,比如调整为 -Xms512m -Xmx512m,它能顺利启动。RocketMQ 5.x 之后支持了 Proxy 组件、gRPC 协议,部署架构更灵活了,但核心概念和 4.x 是兼容的,学老版本的概念到了 5.x 依然能用。
另外,Spring Boot 集成 RocketMQ 时,多 Topic 配置其实很简单:一个 Producer 可以发多个 Topic,不需要为每个 Topic 单独建 Producer。重点配置好 rocketmq.name-server 和 Producer 分组,然后在代码里发不同主题的消息就行。MQ 的消息体就是字节数组,你可以放 JSON 字符串,也可以放其他序列化格式,但记得在消息的 properties 里加业务标识方便排查。
3.4 日常使用中的两个关键提醒
顺序消息是 RocketMQ 的强项,但要用对它,不是把消息发到同一个主题就行。顺序消息必须发到同一个队列,消费端也必须只用一个线程消费这个队列,不然顺序就乱了。一个简单的做法是选一个业务主键(比如订单 ID)作为选择队列的 key,通过 MessageQueueSelector 把同一个订单的消息路由到同一个队列。
另一个坑是消费失败的重试行为。RocketMQ 默认失败会重试 16 次,时间间隔按延迟级别递增,如果消费逻辑里有脏数据导致一直重试,可能造成消息积压。重试 16 次后进入死信队列,要注意监控死信队列数量,这往往是业务 bug 的指示灯。
4. Kafka:大数据场景里的“吞吐怪兽”
4.1 Kafka 的定位:不是消息队列,是分布式流平台
Kafka 最初是 LinkedIn 为解决日志收集问题开发的,后来迅速发展成为大数据生态的事实标准。它的内核设计跟传统消息队列差异非常大:消息不是被消费后就删除的,而是按主题(Topic)分分区(Partition)存储,每个分区内部消息有序递增,通过偏移量(Offset)记录消费位置。这意味着 Kafka 天然支持多个消费者组同时独立读取同一份数据,每个组都有各自的消费进度。这点 RabbitMQ 做不到,RocketMQ 也限制多一些。
这种“持久化 + 多消费者组”的架构,使 Kafka 不仅仅是消息管道,更像一个可重放的日志系统。你可以在 T+1 跑批的时候再消费昨天的数据,也可以把 Kafka 的数据接进 Flink 做实时计算,还可以给实时数仓做数据源。所以才叫“流平台”而不是简单的“消息队列”。
4.2 Kafka 在什么时候该登场
Kafka 的核心优势是吞吐量极高。单个分区就能达到每秒几十万的写入能力,整个集群轻松支持每秒百万级消息。代价是从“消息入队到被消费”的延迟比 RabbitMQ 高一些,通常在几十毫秒到几百毫秒,但它的强项是用吞吐换时间。
典型场景包括:
- 日志采集与管道:应用日志打进 Kafka,由 Logstash、Flink 等下游消费。
- 用户行为埋点:移动端、Web 端的点击、浏览、曝光数据量级极大,Kafka 是核心通道。
- 数据湖/数仓入口:业务数据实时同步到 Kafka,再由计算引擎做数据加工。
- 削峰填谷:秒杀、抢购流量瞬间极高,后端服务无法承受,先全部写进 Kafka,消费者按能力消费。
Kafka 在面试里出现频率极高,核心知识点包括:分区副本机制(Replica 提供高可用)、ISR(In-Sync Replicas)同步副本集合、消费者组 Rebalance 机制、消息幂等 Producer、事务 Producer 等。如果你在准备面试,这些是绕不开的。
4.3 生产消费命令与“启动一次会一直运行吗”的疑惑
很多新手学 Kafka 时都会遇到一个困惑:用命令行工具启动生产者消费者,明明命令执行完了,终端却一直挂着不退出。这是正常的——生产者和消费者都是持续运行的长任务,生产者保持与 Broker 的连接等待你输入消息,消费者持续拉取新消息。不是命令卡死了,你需要新开终端去做另一端的操作。
Kafka 自带了很多命令行工具,从 kafka-topics.sh 创建主题、kafka-console-producer.sh 发消息、kafka-console-consumer.sh 消费消息、到 kafka-consumer-groups.sh 查看消费组状态,全都能通过命令行完成。在一个终端执行:
然后输入消息,回车发送。在另一个终端执行:
就能看到消息实时打印出来。
关于消费者组和消费位置,命令 kafka-consumer-groups.sh --describe 能查到每个分区的 current-offset 和 log-end-offset。如果两者相差很大,说明消费者跟不上生产速度了。有一个地方我自己踩过坑:新消费组默认从最新偏移量开始消费,而不是从头开始。如果团队成员刚上线新消费者,看不到之前的历史消息,第一反应常以为程序写错了,其实这是 Kafka 的默认行为,想要从头消费需要加 --from-beginning 或者手动重置偏移量。
4.4 Docker 部署 Kafka 及可视化工具建议
部署 Kafka 比较繁琐的点在于:Kafka 依赖 ZooKeeper(或 KRaft 模式)管理元数据,两者需要同时启动,网络配置也要小心,否则容器内的连接地址解析错误,客户端会连不上。
用 Docker Compose 部署一个 KRaft 模式的 Kafka(不需要 ZooKeeper)更简洁:
如果用 Docker Desktop 在 Windows 或 macOS 上跑,ADVERTISED_LISTENERS 里的地址很关键。容器里的 Kafka 会把这个地址返回给客户端,如果写成了 kafka:9092 这种容器网络地址,宿主机上的客户端就会连不上。
可视化工具,我推荐 Kafka UI(原来叫 Kafdrop),可以查看主题、分区、消费组、消息内容,部署也很轻量。生产环境里配合 Prometheus + Grafana 监控消费延迟和流量,是标准配置。
4.5 Kafka 消息延迟高,问题出在哪
搜“kafka消息延迟高”的人不少,而且这个问题的排查路径比较固定。最常见的原因有三个:
第一,消费者太少,分区数远大于消费者线程数,很多分区没人消费,消息自然堆积。这时候增加消费者实例数量是最好的解法,注意消费者组内分区会被平分给消费者,消费者数量超过分区数后,多出来的消费者会闲置。
第二,单条消息处理时间太长。可以看消费者日志,如果是业务逻辑调外部接口导致阻塞,那不管 Kafka 参数怎么调都没用,瓶颈在消费端业务。
第三,Broker 端磁盘 IO 满了,或者网络带宽打满了。Kafka 的强项是顺序写磁盘,积压数据量大时,磁盘性能直接决定延迟。生产环境建议用多块 SSD 做 RAID,并在 Kafka 配置里把日志目录分盘存放,避免单盘 IO 排队。
5. 这五个东西到底怎么选:横向对比与选型实战
5.1 一张表看清定位差异
| 选项 | 类型 | 核心协议/模型 | 最强场景 | 吞吐量量级 | 学习曲线 |
|---|---|---|---|---|---|
| MQTT | 通信协议 | 发布/订阅,主题 | 物联网设备接入、边缘通信 | 不适用 | 低 |
| EMQX | MQTT 服务器 | MQTT Broker | IoT 平台海量连接管理 | 单机百万连接 | 中 |
| RabbitMQ | 消息队列 | AMQP,交换机/队列/绑定 | 企业应用集成、灵活路由 | 单队列万级/秒 | 低 |
| RocketMQ | 消息中间件 | 主题/队列,事务消息 | 电商订单、金融交易、消息事务 | 十万级/秒 | 中高 |
| Kafka | 流处理平台 | 分区日志,消费者组 | 日志、埋点、大数据流、削峰 | 百万级/秒 | 中高 |
这张表只能做初步判断。真正选型的时候,还要考虑团队技术栈、运维能力、现有基础设施。比如团队对 Java 更熟、又要写事务消息,RocketMQ 顺手;如果公司已经买了云厂商的 Kafka 服务,那应用接入成本比自建低很多;如果只是企业内部系统之间异步解耦,RabbitMQ 最省心。
5.2 按场景走一遍选型实操
场景一:智能硬件设备接入平台,设备通过 4G/WiFi 上报状态和传感器数据,可能有几万台设备同时在线。
这个直接选 MQTT + EMQX。设备端用 MQTT 协议上报,EMQX 处理设备连接和消息路由,再把数据通过规则引擎桥接到 Kafka 或者数据库。EMQX 支持 Webhook、消息重发布、数据桥接,可以把“设备数据接入”和“业务数据处理”干净地切开。
场景二:电商系统的订单、支付、库存异步解耦,消息要求严格不丢、支持事务、有延迟任务(如超时关单)。
RocketMQ 最合适。事务消息配合延迟消息,几乎是为电商场景量身定做的。这里有个细节要注意:RocketMQ 的消息写入是同步刷盘还是异步刷盘,配置 flushDiskType=ASYNC_FLUSH 时吞吐更高但有少量丢消息风险,用 SYNC_FLUSH 更稳。电商交易链路我建议用同步刷盘,日志链路用异步刷盘即可。
场景三:数据中台,需要把多个业务系统的数据实时同步到数仓、做实时计算。
Kafka 是事实标准。上游业务数据通过 Canal、Debezium 等工具写入 Kafka,下游 Flink/Spark Streaming 从 Kafka 消费做计算,最后入数仓。Kafka 的分区和多消费者组模型,让多个分析任务互不干扰地读同一份数据流。
场景四:企业内部的邮件通知、短信提醒、Webhooks 回调等杂七杂八的消息路由。
RabbitMQ 的 Topic 交换机和死信队列能很好地处理这类需求。想给消息加路由关键字、过期时间、延迟队列,RabbitMQ 的管理界面配起来很直观。不过这里也有个经验之谈:通知类消息一旦量大,消费端积压很常见,最好在接入前就做好幂等处理,否则消费者重启后会重复发送通知得罪客户。
5.3 选型时的三个基本原则
我发现很多团队选型失败,不是在比较功能特性,而是没搞清楚自己的核心诉求。我总结下来,选型时先问三个问题:
第一,你的消息量是真的很大吗? 日均百万条消息以内,RabbitMQ 完全够用。Kafka 的部署复杂度、消费者组概念、副本配置,都是额外的学习成本。为“未来的扩展性”提前上 Kafka,多数情况下不是未雨绸缪,而是给自己找事。真正到了量级大的时候,迁移方案其实是成熟的,不必一开始就为了想象中的高并发买单。
第二,你的数据要求怎样的可靠性和事务性? 如果消息一条都不能丢、还需要跨系统事务,RabbitMQ 和 RocketMQ 都支持 publisher confirm、事务消息等机制,Kafka 虽然也支持幂等和事务,但使用成本高,语义和业务事务的结合没有 RocketMQ 直接。
第三,你的团队运维能力如何? Kafka 集群要做分区副本均衡、磁盘规划、监控告警,picky 得很;RocketMQ 的 Broker 和 NameServer 部署相对简单,但版本迭代快,社区资料也远没 RabbitMQ 和 Kafka 多。如果公司没有专职中间件运维人员,优先选择托管服务(云厂商 RKT、Kafka、RabbitMQ 托管版)比自己搭集群稳妥得多。
6. 串起来理解:一条主线把五兄弟理顺
看到这里你会发现,这五个词其实可以串在一条主线上:设备端和嵌入式端跑的是 MQTT 协议,EMQX 是承载这些设备连接的服务端;企业内部系统之间做消息路由,用 RabbitMQ;核心电商链路要事务消息和延迟消息,上 RocketMQ;海量日志和实时计算的数据管道,交给 Kafka。
它们之间不是替代关系,更多是分工关系。一个大型 IoT 平台里,EMQX 接到设备消息后可以桥接到 Kafka 做数据存档;订单服务把消息发给 RocketMQ,某个模块需要把变动同步给大数据平台时,也可以用 rocketmq-connector 或者 CDC 工具把数据转发给 Kafka。在我的实际项目里,这四类中间件经常同时存在,各管一摊,配合起来相安无事。
从学习路径的角度,我给新人的建议是:先花两周把 RabbitMQ 玩熟,掌握交换机、队列、绑定、死信这些核心概念,这是一切消息中间件的地基。然后学 Kafka,重点理解分区、副本、消费者组为什么这么设计,这对建立起“分布式系统里数据怎么流动”的直觉非常有帮助。之后再学 RocketMQ 的事务消息和延迟消息,你会很容易理解它相比 RabbitMQ 多了什么。最后接触 MQTT 和 EMQX,你会发现有了前面的基础,IoT 接入层对你来说也没那么神秘了。
我见过不少工程师,学了一堆中间件的 API 用法,但遇到问题时还是不知道去哪查、不知道消息到底卡在哪一跳。真正有用的不是你会调 convertAndSend 还是 producer.send,而是你脑子里有一张“消息从哪来、到哪去、经过哪个 Broker、用什么协议、消费到哪了”的全链路地图。把这五个东西的关系理清了,你已经比大多数只刷过教程的人强了。后续做技术方案时,尽量拿一个最小可行项目去验证你的选型,拿生产环境练手永远是学习消息中间件最快的路。