MQTT Broker集群选型对比:FreeMQTT plus vs EMQX vs VerneMQ vs Mosquitto 做IoT的人几乎都要面对mqtt broker集群方案选型这一关。最近有好几个做设备接入的朋友都在问FreeMQTT plus正好我把这个方案的集群实现和EMQX、VerneMQ、Mosquitto这些主流通用选型放一起做了次完整对比。这篇文章不玩虚的直接说清楚每个方案的核心机制、集群能力边界、运维成本和适合场景帮你判断自己项目到底该选哪个。先说清楚一件事MQTT broker集群不是为了炫技而是连接数、消息吞吐和可用性三者到了单机扛不住的时候必须走的一条路。但集群不等于把多个broker进程扔在一起也不等于搞个负载均衡放在前面就完事。如果拓扑、路由同步、会话迁移、消息去重这些底层机制没想明白上线第一天很可能就是事故现场。这篇文章适合三类人一是正在做IoT平台选型的技术负责人二是已经在跑MQTT服务但遇到单机瓶颈、准备上集群的运维和开发三是对FreeMQTT plus好奇、想了解它和主流方案差异的架构师。我会从选型指标开始拆解再逐步深入到每个方案的核心机制和实操细节。1. 集群选型先想清楚这五个维度再谈对比1.1 集群到底解决什么问题很多人对集群有误解以为把MQTT broker部署成多副本、前端挂个负载均衡器就是集群。实际这里有两类问题要分开看一类是解决连接接入的扩展问题比如单机最多撑10万连接现在要接50万个设备需要把连接分散到多台机器上另一类是解决消息处理的可靠性问题比如某台机器宕机了它上面挂着的设备和订阅关系不能全部丢需要另一台机器接管。这两类问题对应的集群设计思路是不同的。前者更像开多个收银台每个台子独立服务一部分顾客核心是分流后者更像厨房里的炒菜师傅互为备胎某个灶台坏了其他灶台要把活接过去核心是热备和状态共享。MQTT的集群方案通常要同时处理这两件事既要转发客户端连接又要在broker之间同步订阅关系和会话状态。如果在选型时没有把这两层需求拆开想清楚后面一定会遇到要么扩展性不够、要么故障恢复时间太长的问题。还要注意集群引入了新的复杂性至少包括节点间通信、状态一致性、数据去重和脑裂处理。这些开销在单机模式下是完全不存在的。所以先问自己一句当前业务是真的需要集群还是单机加少量调优就能满足我在评估FreeMQTT plus和主流方案时第一步永远是看连接规模、消息速率和可用性要求而不是先选技术栈。这一步想清楚了后面所有的对比才有意义。1.2 选型时必须盯住的5个硬指标实操中我衡量一个MQTT broker集群方案是否靠谱主要盯5个指标连接规模、消息吞吐、可用性、扩展边界、运维成本。下面这个表格是我在选型时固定用的检查清单。指标含义对选型的影响连接规模单节点和集群能支撑的最大并发TCP连接数决定设备接入层的部署架构和服务器数量消息吞吐每秒能处理的发布/订阅消息数尤其是QoS 1和QoS 2场景决定业务高峰期会不会积压消息可用性节点宕机、网络分区时服务能否继续、恢复耗时多长决定故障对业务的影响面扩展边界集群能否横向扩容扩容时需不需要停服决定未来规模增长时的操作成本运维成本部署、监控、升级、排查问题的综合复杂度决定需要多少人力和工具投入连接规模是最容易比出差距的指标。Erlang生态的EMQX、VerneMQ在并发连接处理上有天然优势单个节点可以撑几十万连接集群能到百万级FreeMQTT plus和Mosquitto这类轻量级方案单节点连接数通常在几万到十几万级别但在中小规模场景下完全够用。消息吞吐是另一个容易踩坑的地方。很多方案在连接数上表现很好但一旦消息体量大、发布频率高转发链路就开始出现延迟抖动。这里要特别关注QoS 2的语义因为QoS 2要求端到端的消息不重不漏实现复杂度远高于QoS 0和QoS 1集群模式下还需要跨节点去重对吞吐的影响很明显。可用性要看两个数字RTO恢复时间目标和RPO恢复点目标。有的方案能做到秒级故障转移但消息会丢一部分RPO不为零有的方案强调消息不丢恢复时间却要几十秒甚至更久。这两者之间是直接权衡没有十全十美的方案。我见过不少团队上线时只盯着吞吐量把可用性指标抛在脑后结果一次半夜宕机直接让全业务停了两个小时。2. FreeMQTT plus 是怎么实现集群的2.1 从单机到集群的设计思路我第一次接触FreeMQTT plus是在一个边缘计算网关项目里当时需要在一台配置不高的嵌入式服务器上跑轻量级MQTT服务同时还要和另一台网关形成互备。传统方案EMQX对这种场景偏重部署包和内存占用都比较大FreeMQTT plus刚好踩中了这个需求点。FreeMQTT plus在单机版基础上主要增强了三个能力节点间集群通信、会话和订阅信息的同步、以及消息转发路由。它的集群模式走的是去中心化设计每个节点都是对等的broker节点之间通过内部协议互相感知。这和EMQX早期的做法有些类似但实现更轻量底层不依赖Erlang虚拟机部署起来简单得多。它使用了raft协议来维护集群元数据和订阅关系的一致性。这里先解释一下raft简单来说就是多个节点选出一个leader来负责状态变更其他节点同步复制当多数节点确认后这次变更才算成功。这种机制的好处是能保证一致性坏处是写路径需要跨节点确认订阅关系的变更响应会有一定的额外延迟。实际使用中订阅关系变化的频率远低于消息发布的频率所以这个延迟在绝大多数场景下完全可以接受。FreeMQTT plus的消息转发不走raft通道而是走节点间的数据平面直连这样消息发布路径不会被一致性协议拖慢。也就是说它把控制平面和数据平面做了分离控制平面用raft保证订阅关系、会话信息、路由表的一致性数据平面用高效的消息通道来完成实际的发布订阅转发。这个设计和目前主流分布式消息系统的思路是一致的也是它能在轻量级前提下保持较好吞吐的原因。2.2 FreeMQTT plus 的集群搭建实测FreeMQTT plus的集群搭建是我见过的方案里比较省事的。它支持通过配置文件直接声明集群成员不需要单独部署注册中心或发现服务。这个设计对中小团队特别友好少了ZooKeeper或etcd这么一层额外组件整个系统的运维复杂度一下子降下来了。下面是一份简化后的集群节点配置参考。三个节点组成一个集群每个节点配置文件里声明了自己的节点ID、监听地址和集群成员列表# 节点1配置示例 node: id: mqtt-node-1 listen: 0.0.0.0:1883 cluster: enabled: true listen: 0.0.0.0:7883 seeds: - mqtt-node-1:7883 - mqtt-node-2:7883 - mqtt-node-3:7883# 节点2配置 node: id: mqtt-node-2 listen: 0.0.0.0:1883 cluster: enabled: true listen: 0.0.0.0:7883 seeds: - mqtt-node-1:7883 - mqtt-node-2:7883 - mqtt-node-3:7883# 节点3配置 node: id: mqtt-node-3 listen: 0.0.0.0:1883 cluster: enabled: true listen: 0.0.0.0:7883 seeds: - mqtt-node-1:7883 - mqtt-node-2:7883 - mqtt-node-3:7883三个节点都配置了同一个seeds列表启动后会自动发现彼此并尝试建立集群连接。当多数节点这里是2个都确认了彼此状态集群就进入健康运行状态。客户端可以从任意节点接入不需要区分哪个是入口节点。这个实操下来确实方便我第一次部署从解压安装包到三节点集群正常收发消息只用了不到半小时。验证集群是否正常工作时最简单的办法是分别从两个不同节点用MQTT客户端建立连接一个订阅某个主题另一个向同一主题发布消息如果消息能正常收到说明集群路由已经通了。还可以用FreeMQTT plus自带的命令行工具查看节点状态它会展示每个节点的连接数、订阅数和集群健康状态。2.3 部署中的注意事项FreeMQTT plus集群模式部署时有几个细节必须注意。第一个是网络分区场景。raft协议要求多数节点可用才能提供一致性服务假设三节点集群中有一个节点和其他两个节点网络断开断开的节点会进入只读状态不能处理订阅变更和客户端上线。这一点在跨机房部署时要特别小心如果网络抖动频繁客户端会不断掉线重连。第二个细节是客户端会话的粘性问题。MQTT的会话状态分为clean session和persistent session两种。FreeMQTT plus在集群模式下持久会话的状态会绑定到客户端首次接入的那个节点。如果这个节点宕机了会话能从其他节点的同步数据中恢复但恢复过程中客户端需要重新连接这个切换会有短暂的不可用窗口。第三个细节是升级顺序。FreeMQTT plus的版本迭代比较快跨版本升级集群节点时我建议先在测试环境验证新版本和旧版本的集群通信兼容性再在线上逐个节点滚动升级。曾经有一次我直接在生产环境升级了其中一个节点结果新版本的集群协议和旧版本不匹配导致节点始终无法加入集群排查了半个小时才发现是版本问题。3. 主流 MQTT Broker 集群方案横向对比3.1 四类技术栈的阵营划分说实话现在市面上能用于生产环境的MQTT broker集群方案按底层技术栈划分大概有四个阵营。把这些阵营搞清楚了选型思路基本就清晰了一半。第一个阵营是Erlang生态代表是EMQX和VerneMQ。Erlang天生适合高并发和分布式进程模型非常轻量所以这个阵营在连接规模上有天然优势。EMQX目前是社区活跃度最高的方案之一集群能力成熟插件生态丰富国内很多IoT平台都在用它。VerneMQ在消息存储和复制上做过不少优化但社区活跃度和文档完善程度比EMQX差一些。第二个阵营是Go生态FreeMQTT plus、Giotto这类方案都属于这个阵营。Go语言部署简单、并发处理也够用、内存占用低适合资源受限的边缘场景。FreeMQTT plus算是这个阵营里比较有代表性的轻量级集群方案尤其适合中小规模接入。第三个阵营是C/C生态代表是Mosquitto和NanoMQ。Mosquitto是Eclipse基金会的项目单机性能好但它本身不提供集群功能要做集群需要自己用负载均衡加共享存储的方式拼装前提是要接受它相对简单的订阅同步机制。NanoMQ在边缘侧表现不错资源占用极低集群模式还在完善中。第四个阵营是企业级商业方案代表是HiveMQ。HiveMQ的集群能力很完善支持大规模部署和跨机房容灾但授权费用不低一般中小企业不太会选它作为第一方案。3.2 对照清单FreeMQTT plus vs EMQX vs VerneMQ vs Mosquitto下面这张表是我在多次测试和实际项目基础上整理的对比清单。注意里面有些数字会因硬件配置和测试方法不同而有出入但相对差异是有参考价值的。维度FreeMQTT plusEMQXVerneMQMosquitto自组集群单节点连接数5万~10万级50万~100万级50万级1万~5万级集群模式内置raft协议内置分布式Erlang内置复制协议无原生集群消息存储内存 可插拔后端内置消息存储内置消息存储内存存储QoS 2支持支持支持支持支持共享订阅支持支持支持需插件最小部署节点数31单机非集群2需自行组装部署包体积小较大中等小运维门槛低中中高中但集群方案复杂可观测性基础指标丰富插件和API基础Prometheus基础跨机房容灾有限支持支持支持较难做社区活跃度中等高中高单节点连接数这里要特别说明一下。EMQX能做到百万级连接主要得益于Erlang的进程模型每个连接对应一个轻量级进程内存开销极小。FreeMQTT plus用的是Go的goroutine连接管理能力也在不断优化但和Erlang这种为软实时而生的并发模型相比在超高并发场景下仍然有差距。正常IoT项目做到几万到十几万连接已经很不少了不需要盲目追求百万级。消息存储方面EMQX在4.x时代引入的内置数据库和5.x时代的增强存储机制让它在消息持久化和重放方面能力更强。FreeMQTT plus走的是内存加可插拔后端的路线对于需要大量消息落盘的场景会多一些工程工作。共用订阅这个功能很关键它允许多个客户端实例共同消费同一个主题的消息是实现负载均衡消费的必备能力。据我测试FreeMQTT plus和EMQX的共享订阅都支持得不错Mosquitto的共享订阅从2.0版本成为正式特性后才相对好用。3.3 几个最容易被忽略的差异点除了表格里的显性指标有几个隐性差异点是真正会在生产环境里坑人的值得单独拿出来说。第一个是节点间消息转发的效率和去重机制。MQTT集群里当客户端A连在节点1上订阅了主题T客户端B连在节点2上向主题T发布消息时节点2需要把消息转发给节点1再由节点1推送给A。这个跨节点转发的路径如果实现不高效消息延迟和数据传输量都会明显增加。EMQX的分布式Erlang底层有成熟的节点通信机制转发路径相对稳定FreeMQTT plus的数据平面直连设计也够用但在节点数量较多时路由表和转发路径的管理会更复杂。第二个是持久化会话的迁移策略。MQTT协议规定持久会话在客户端断开后要保持消息和订阅状态。集群模式下这个状态放哪里、如何迁移直接决定了客户端重连的体验。EMQX提供了会话的分布式存储能力客户端从任意节点重连都能恢复会话FreeMQTT plus采用绑定初始节点的策略故障切换时会有短暂的重连窗口Mosquitto的自组集群模式要处理持久会话基本只能靠共享后端存储而Mosquitto本身提供的会话状态同步能力很弱。第三个是共享订阅的负载均衡策略。共享订阅支持轮询、随机、哈希等多种策略不同策略对消息分配的影响很大。EMQX支持多种分配策略并且可以在主题级别配置FreeMQTT plus在共享订阅的灵活度上稍逊一筹但基础的轮询和哈希都用得起。如果业务对消息消费顺序有严格要求需要注意哈希策略能保证同一客户端ID的会话消息总是发给同一个订阅者轮询则不保证。第四个是权限和鉴权的集群统一管理。MQTT服务在规模上来之后ACL访问控制列表和客户端认证信息需要跨节点统一。EMQX可以通过内置数据库或外部数据库统一维护ACLFreeMQTT plus也支持集成外部数据库做集中认证但配置步骤上会多一点工作。选型时一定要把权限管理方式问清楚否则几十个节点各自维护一份ACL表很快就乱套了。4. 场景化选型到底该用哪一个MQTT集群方案4.1 设备量大、高并发场景优先看EMQX和VerneMQ如果你的业务需要支撑的设备连接量在几十万甚至百万以上比如大型车联网平台、智慧城市级别的物联网中台选型重点应该放在连接能力和集群成熟度上。EMQX几乎是最稳妥的选择它的百万连接、热升级、共享订阅、规则引擎都是经过大规模生产环境验证的。VerneMQ在连接规模上也不差而且它对MQTT协议的实现很完整尤其适合对消息吞吐有苛刻要求的团队但它的社区生态和可观测性建设相对EMQX弱一些排障时能参考的资料少。这个场景下我不建议选FreeMQTT plus或Mosquitto自组集群。FreeMQTT plus的连接规模上限决定了它更适合中小场景硬要往大规模上凑的话可能需要部署多套集群然后在上层做主题或设备维度的路由拆分这个架构复杂度远高于直接上一套大集群。我自己见过一个团队用Mosquitto拼了个粗略的集群方案上线初期没问题到设备量涨到预期规模一半时订阅同步带来的消息丢失和重复问题开始集中爆发最后只能半夜紧急迁移到EMQX。这种推倒重来式的返工成本比一开始选型多花一周时间要高得多。4.2 边缘网关和嵌入式场景选Mosquitto或NanoMQ在边缘网关、智能网关、工控设备、开发板这类资源受限的环境里Mosquitto和NanoMQ仍然是最合适的选择。它们部署包极小、内存占用低单机就能在小型设备上稳定跑很久。而且边缘节点通常不是集群的重点因为边缘侧设备量小一台网关扛几百上千个连接是常态不需要为了连接规模去构建复杂集群。边缘节点如果要做高可用一般是通过主备切换加虚拟IP的方式实现而不是做分布式集群。在这个场景里引入集群是完全没必要的。我见过有人在一台树莓派上部署了三节点的集群跑起来之后内存直接爆掉这就是典型的没有评估资源就盲目上复杂方案。边缘侧真正需要的是轻量、稳定、容易维护FreeMQTT plus同样适合边缘侧部署它的资源占用比Mosquitto高一些但比EMQX低很多用在性能稍好的边缘服务器上是完全可以的。如果你在边缘侧有多个节点需要互备FreeMQTT plus的集群能力会是一个额外的加分项因为它至少有一个原生方案能实现节点间状态同步。4.3 中小型IoT平台优先考虑FreeMQTT plus对绝大多数中小型IoT平台、智能硬件创业公司、工厂内部数据采集系统来说FreeMQTT plus属于那种“配置刚刚好”的方案。假设你的设备量在几千到几万台之间消息速率在每秒几百到几千条需要2到3个节点组成高可用集群同时团队没有专门的MQTT运维专家FreeMQTT plus的低运维门槛优势会非常明显。我团队做过一个实际项目业务是工厂设备的实时状态采集设备总量大概1.2万台高峰时每秒钟产生1500条左右的消息。当时评估了EMQX和FreeMQTT plus两个方案EMQX各项能力都更强但部署和运维需要专门的Erlang知识背景FreeMQTT plus三节点集群只花了一天就部署完运行了大半年基本没出过需要人工介入的问题。消息端到端延迟在5毫秒以内集群的CPU和内存占用也始终维持在一个很低的水平。当然选FreeMQTT plus就要接受它的一些局限比如跨机房容灾能力有限、官方文档和社区资源不如EMQX丰富、扩展功能的生态还需要自己积累。但这些局限在中小场景下通常不会成为瓶颈。4.4 企业级高合规需求选HiveMQ或EMQX企业版最后一个场景是金融、能源、政务这类对合规、审计、SLA有硬性要求的企业级项目。这类项目的特点是不差钱但对稳定性和支持服务要求极高。HiveMQ在企业级市场深耕多年集群能力、安全机制、审计日志都很完善还提供商业技术支持选它基本不会出错。EMQX企业版在国内市场做得也不错针对国产物联网场景有大量优化团队响应速度快而且支持国产化环境部署这些都是很多央企和国企客户非常看重的点。FreeMQTT plus和社区版EMQX在这个场景里会比较吃亏主要缺少企业级的支持服务和严格的性能保障承诺。不是说社区方案技术不行而是出了问题没有人给你兜底也没有SLA赔付机制这在企业采购流程里是硬伤。4.5 选型决策的实操路径我在选型时根据自己的经历设计了一套比较实用的决策路径可以参考一下先明确设备连接数和消息QPS的预期峰值再梳理可用性要求确定RTO/RPO指标然后看团队已有的技术栈和运维能力最后才是上手做POC概念验证测试。其中POC这一步最容易偷懒但也最不应该偷懒。我建议至少做三轮验证第一轮用官方压测工具测吞吐量和连接数第二轮模拟节点宕机观察故障恢复耗时和消息丢失情况第三轮跑一周稳定性测试观察内存泄漏、CPU波动和日志输出情况。同一套测试流程跑完所有备选方案用数据说话而不是凭着网上的口碑和别人的经验做决定。把这三轮测试结果和运维门槛、商业成本放在一起一对比选型结论基本就是水到渠成的事情。5. 常见坑位与排查实录5.1 客户端连接总被负载均衡踢掉的坑不少团队用FreeMQTT plus集群时会在前端加一台负载均衡器分发客户端连接。最常见的故障现象是客户端连接建立后每隔一段时间就会被断开重连表现像是被踢掉。排查一圈下来发现问题出在负载均衡器的空闲超时时间上。MQTT连接建立之后如果客户端没有消息往来连接处于空闲状态此时负载均衡器默认的空闲超时机制会切断连接而客户端没有及时感知重新订阅就会失败。解决方案很简单把负载均衡器针对MQTT端口的空闲超时时间调大或者在客户端开启MQTT的心跳保活机制并确保心跳间隔小于负载均衡器的超时时间。这里要注意的是MQTT的心跳协议是应用层的心跳负载均衡器不一定能感知到。有些四层负载均衡器会把TCP层面的活动也看作连接活跃有些则只看是否有数据包通过不同产品的行为不一致。所以最好在部署环境里做一次长连接稳定性验证连续跑24小时甚至48小时观察有没有被踢掉的连接。5.2 节点间状态不同步导致的重复消息我在测试FreeMQTT plus集群时遇到过一个问题客户端A订阅主题T客户端B向主题T发布消息正常情况下消息只应该被推送一次。但有时候订阅端的消费者会连续收到两条相同内容的消息。深入排查后发现这是由于客户端A在连接断开后快速重连而重连过程中节点间的订阅关系同步还没有完全收敛导致新旧两个节点都认为自己是这个订阅关系的负责节点同一份消息就被转发了两份。这是分布式系统中比较典型的“脑裂”场景。解决的思路有两个方向一是从客户端做幂等处理消费者根据消息ID或业务主键去重二是从服务端调整确保客户端重连时旧节点上的订阅关系能够被新节点正确接管并清理。FreeMQTT plus在后续版本中优化了会话迁移逻辑但作为使用方我们不可能完全依赖服务端在消费端做幂等处理仍然是最稳妥的兜底方案。5.3 集群节点掉线后不能自动恢复另一个踩过的坑是集群中的一个节点因网络抖动和另外两个节点失联网络恢复后它一直处于“重连中”状态始终不能自动加入集群。排查发现是和节点ID相关的。FreeMQTT plus的集群依赖节点ID来识别成员如果节点重启时ID发生了变化例如某些虚拟化环境下主机名变化导致默认生成的ID改变其他节点就会把它当作一个不认识的节点拒绝它加入集群。解决办法是给每个节点指定固定的节点ID建议直接配置成有业务意义的名称比如mqtt-node-01、mqtt-node-02避免依赖自动生成。同时迁移容器或虚拟机时要注意保留配置文件和持久化数据目录否则节点ID变更会导致集群成员不识别。这类问题在EMQX集群里同样存在EMQX的节点名机制也要求升级或迁移时保持一致。5.4 网络分区的选择可用性还是一致性最后一个想重点谈的坑是网络分区时的行为差异。MQTT集群在跨机房部署时最怕的就是两个机房之间的专线抖动导致集群被分成两半。此时不同方案的表现差异很大。EMQX在默认配置下会尽可能保持服务的可用性代价是可能出现消息冲突和需要之后的人工协调FreeMQTT plus因为使用了raft协议在分区场景下会倾向于保证一致性只有多数派那一边的节点能继续正常服务少数派节点虽然还能接受客户端连接但无法处理订阅变更和持久会话建立客户端连上去之后往往会发现什么都干不了。这个选择本身没有绝对的对错取决于业务诉求。如果业务更看重任何时候都能发布消息要选偏向可用性的方案并处理好冲突如果业务更看重消息不能错不能乱FreeMQTT plus这种强一致性的做法反而更合适。关键是选型前要和业务方明确这个权衡不要等到网络抖动发生了才发现两边预期不一致那才是真正的灾难。根据我个人经验MQTT broker集群选型最怕的不是技术差距而是需求定义不清楚。先把预期规模和可用性指标定下来再用统一的方法做POC验证同时一定要考虑到自己能投入的运维精力最后选出来的方案不一定是参数最漂亮的但一定是最适合自己的。FreeMQTT plus在中小规模高可用场景里表现超出了我的预期尤其是它的低运维门槛和内置集群能力让一个三人小组也能轻松维护一套生产级别的MQTT服务这一点是很多大型方案反而不具备的优势。