这两年做物联网网关选型,我身边不少团队都在认真琢磨一件事:手里正在用的 Mosquitto 或 EMQX,要不要换成国产方案。一个比较逗的细节是,很多人在调研“国产替代”时绕了一大圈,回头才发现 EMQX 本身就是国内团队主导的开源项目。折腾半天,最终要回答的问题其实不是“国产不国产”,而是“这套开源的东西拿来做商用项目,版权上到底稳不稳”。
这篇文章想聊透两件事:一是 Mosquitto、EMQX 以及几类国产 MQTT 协议栈在开源许可证上的真实差异,二是如果你决定迁移,从技术选型到灰度切换,到底该怎么落地。适合正在做物联网平台、边缘网关、工业数据采集的技术负责人和架构师看,也适合那些单纯想搞清楚“我用开源 MQTT 会不会有天被发律师函”的开发者。
1. 替代需求从哪里来:先分清你要换的是“协议栈”还是“broker”
1.1 一个词被用烂了:MQTT“协议栈”到底指什么
聊替代之前,必须先把概念掰清楚。很多人把“MQTT 协议栈”和“MQTT 服务器(broker)”混为一谈,选型的时候很容易对不上号。
MQTT 协议栈在嵌入式领域通常指运行在设备端、实现 MQTT 协议编解码的客户端库。MCU 通过它连接 broker,完成发布订阅。这类代码要求极轻、内存占用小、能跑在 RTOS 甚至裸机上。常见的有 Eclipse Paho Embedded C、LwMQTT,以及各种国产 RTOS 自带的组件。设备端这一层,跟 Mosquitto / EMQX 根本不是竞争关系,反而是它们在 TCP/IP 网络之上的“上游依赖”。
broker 则完全不同。它就是 MQTT 的服务端,负责接收所有客户端的连接、处理订阅关系、转发消息。Mosquitto 和 EMQX 就是这个位置的角色。所谓“替代 Mosquitto / EMQX”,真正替代的是 broker 这一层。
这个区分是后面所有讨论的前提。你会发现,版权风险最大的恰恰不在设备端协议栈,而在服务端。服务端一旦集成到你的产品里再对外分发,许可条款的边界就变得非常敏感。
1.2 开源不等于免责:“运行”和“分发”是两条完全不同的路
我见过太多团队踩同一个坑:看到 GitHub 上写着开源协议,就觉得拿去商用天经地义。这是开源软件最大的误解。
判断你有没有许可证义务,核心看两个动作:运行,还是分发。
如果你的业务只是把 Mosquitto 或 EMQX 跑在自己的服务器上,作为自建物联网平台的消息通道,客户通过设备或 App 来连,你并没有把 broker 的代码作为产品的一部分交付给别人。这种情况属于“运行”,就算用的是强 copyleft 协议,通常也不触发开放源码义务。很多商业公司跑着开源软件,法律上清清白白。
一旦你把 broker 的源代码改过之后,编译进自己的产品里,卖给客户或交付给合作伙伴,这就构成了“分发”。此时许可证的每一项条款都会精确约束你:要不要公开修改后的源码?能保留闭源的商业秘密吗?能收取授权费吗?在国产化的大背景下,很多团队是想把整套系统做成产品交付出去的,这个问题就躲不开了。
所以接下来拆许可证时,你心里要始终带着这句话:我是运行它,还是改它、发它。
2. 开源版权清算:Mosquitto、EMQX 和国产方案的许可边界
2.1 Mosquitto 的双许可:很多人还停留在“GPL 恐惧”里
网上搜 Mosquitto 版权,很多老文章还在说 GPL。实际上 Mosquitto 2.0 开始已经是双许可证模式了。
Eclipse Mosquitto 采用 EPL 2.0 与 EDL 1.0 双许可,使用者可以任选其一。EPL 2.0(Eclipse Public License)属于弱 copyleft,核心义务是:如果你修改了 Mosquitto 的源码,并且以源代码或目标代码形式分发,那么修改的那部分代码必须开源。但 EPL 有个特点,它对“修改”的界定比较聚焦于文件级,不会像 GPL 那样传染整个衍生作品。也就是说,你可以在一个闭源的大系统里调用或集成 EPL 组件,只要遵守修改部分的开源义务,整体项目可以不被强制开源。
EDL 1.0(Eclipse Distribution License)就更宽松了,基本是 BSD 风格,允许自由使用、修改、商用,只要保留版权声明。所以 2.0 之后,把 Mosquitto 内嵌到商业产品里,许可证障碍其实比过去小很多。
需要注意一个细节:Mosquitto 1.x 时代的许可是 EPL 1.0 / GPL 2.0 加例外条款,那个例外给了动态链接等场景一定的自由度,但解释起来很绕。如果你维护的老项目还基于 1.x,建议重新审视版本和许可。
2.2 EMQX 的商业逻辑:开源核心加上企业版边界
EMQX 是国内团队主导的项目,这一点让很多“国产替代”调研变得有些黑色幽默。它的开源版采用的是 Apache 2.0 许可证,这是目前对商业最友好的开源协议之一。
Apache 2.0 允许自由使用、修改、商用、再分发,不要求衍生作品开源,唯一比较硬性的要求是:必须保留原始版权声明、NOTICE 文件,并且如果你用了它的专利,将来不能反过来告它专利侵权。对做商业产品的团队来说,Apache 2.0 几乎不会成为阻碍。
那风险在哪?在于 EMQX 的发行版形态。它提供的开源版本是功能裁剪过的社区版,集群管理、规则引擎的高级功能、多区域同步、某些企业级认证插件都在企业版里。企业版走商业授权,代码不公开。换句话说,你基于 Apache 2.0 的开源代码自己改造是合法的,但如果你想直接用官方打包好的完整能力,尤其是生产级集群,那本来就是商业软件的范畴。
做选型时这是一个关键认知:EMQX 的“开源”和“免费可用”是两回事。开源版永远存在,但开源能力天花板也是刻意设计的。
2.3 国产候选的许可证现状:从 Apache 到 MIT 都有
国产 MQTT broker 和协议栈这几年冒出来不少。一些是公司主导的社区项目,一些是行业解决方案附带的内部组件。我评估过的几个方向是这样的:
- 基于 Go 语言实现的开源 MQTT broker,比如 Gmqtt,许可证是 Apache 2.0,支持 MQTT 3.1.1 和 5.0,具备消息持久化、ACL、HTTP API 等基础能力。它的优势是纯 Go 部署简单、内存表现好、社区活跃度能看得见。
- 一些厂商提供的工业物联网网关自带“轻量级 MQTT 服务”,本质上是在开源协议栈基础上做二次开发和封装,许可证通常没有公开文档,需要逐一和厂商确认。
- 嵌入式设备端用得最多的 LwMQTT,MIT 许可证,商用几乎无负担。RT-Thread 软件包中心里的 MQTT 组件,底层也是基于 Paho 系列做的封装,许可证体系跟着上游走。
做国产方案评估时,我的建议直接列一张对照表:
| 组件 | 典型项目 | 许可证 | 商用分发风险 |
|---|---|---|---|
| 嵌入式客户端协议栈 | LwMQTT | MIT | 极低,保留版权声明即可 |
| 嵌入式客户端协议栈 | Paho Embedded C | EPL 2.0 / EDL | 低,修改分发注意 EPL 条款 |
| 服务端 broker | Mosquitto 2.x | EPL 2.0 / EDL 双许可 | 低,但要把许可证文件随产物保留 |
| 服务端 broker | EMQX 开源版 | Apache 2.0 | 低,注意企业版功能边界 |
| 服务端 broker | Gmqtt 等国产开源 | Apache 2.0 | 低,依赖自行审计 |
2.4 判断商用风险的三个关键问题
与其听别人说某个方案“能不能用”,不如自己用一套框架去判断。我给客户做评估时,只会问三个问题:
第一,这个项目的许可证文件到底写得清不清楚。很多国产项目 GitHub 主页挂着 MIT,但代码里某个核心模块拷贝了别家 GPL 代码且没有声明,这种“夹带私货”是比许可证本身更大的黑洞。因此无论选什么方案,先做一遍依赖扫描。
第二,你的交付形态是“运行”还是“分发”。如果只做自用平台,许可压力本来就小;如果做产品交付,就要把每一个组件的许可证归档到交付物里,并核对修改边界。
第三,项目是否有持续维护的迹象。Apache 2.0 救得了一时的版权问题,救不了一个停更三年的项目。真出安全漏洞时,开源许可证不会帮你写补丁。
框架比结论更重要。拿这套问题去套任何国产方案,都比直接问“哪个是安全的”靠谱得多。
3. 国产协议栈与 broker 的选型实操:别被性能指标带偏
3.1 嵌入式设备端:MCU 上的轻量级替代要关注什么
如果你的场景是 STM32 + lwIP 这类 MCU 环境,替换方案更多是协议栈层面的选择。很多国产模组的出厂 SDK 里其实已经集成了 MQTT 客户端,比如 4G 模组用 AT 指令直接连 broker,WiFi 模组自带 MQTT 库。评估这类方案时,我建议关注四个点:
一是内存占用,MQTT 协议栈在 MCU 上通常要配合 TCP/IP 协议栈一起跑,申请缓冲区时非常考验资源预算。二是断线重连机制,很多国产协议栈把重连做成黑盒,参数又不开放,真到弱网环境就抓瞎。三是 TLS 支持,很多轻量级实现只支持 TCP 直连,上 TLS 后 flash 占用直接翻倍,低端芯片根本扛不住。四是许可证声明,哪怕 MIT 协议也要求保留声明,出货之前把这些文件放进固件交付包是最容易被忽略的合规动作。
移植层面,LwMQTT 这类协议栈通常只需要你实现网络层接口,比如 connect、read、write、disconnect 四个函数,然后在主循环或者 RTOS 任务里周期性调用 mqtt_yield 处理收发事件。上手门槛很低,协议栈本身不关心底层是 lwIP 还是其他 TCP/IP 协议栈,这也是它能大范围移植的根本原因。
3.2 服务端 broker:单机替换容易,集群替换难
服务端替换的真正分水岭,不是协议解析能力,而是集群和生态。
MQTT 协议本身只定义客户端和 broker 之间的通信,客户端的 SDK 基本不受 broker 影响。你换 broker,Android 端、iOS 端、Node-RED、Kepware 这些标准 MQTT 客户端根本无感知。这就是为什么很多人觉得“替换很简单”,因为设备和后端连着 broker 的地址,把地址切过去就行。
麻烦的是 broker 周边能力。EMQX 集群能水平扩展、能配置规则引擎直接转发到数据库或 Kafka,Mosquitto 用桥接实现简单的多机互联,而很多国产 broker 单机跑得不错,集群能力要么没有,要么比较原始。如果你的业务将来要支撑几万设备,这一步评估绝对不能跳过。
我给的选型建议是按场景切分:边缘网关内嵌 broker,优先看轻量和许可证;中心机房大规模部署,优先看集群、监控、鉴权、消息追踪这些工程化能力;工业现场,反而要关注它支不支持 MQTT over WebSocket、TLS 双向认证这些偏门但现场常需要的功能。
3.3 用功能清单约束选型,别被并发数带着走
很多厂商宣传时喜欢晒压测数据:单机十万连接、百万消息。我要泼一盆冷水:那个数据测的是理想网络环境下的纯协议栈性能,跟你真实业务根本不是一回事。
正确的做法是先列一份功能清单,再拿着清单去筛方案。我习惯起点是:
- 支持哪个 MQTT 版本?只支持 3.1.1 还是能上 5.0?
- QoS 0/1/2 是否全部实现?有没有已知 bug?
- 遗嘱消息、保留消息、持久会话语义是否标准?
- 有没有内置认证?用户名密码、Token、TLS 双向认证是否都覆盖?
- WebSocket 监听、HTTP 桥接这些外部接入能力是否具备?
- 有没有监控指标接口?最好能直接推到 Prometheus 这类系统。
清单列完,你会发现很多国产 broker 在基础协议项目上是合格的,但在运维监控和生态集成上会暴露短板。并发数再好看,卡在这些地方才是最痛的。
4. 替换落地:从 Mosquitto / EMQX 迁到国产 broker 的完整路径
4.1 环境准备:容器化部署和参数初始化
无论换到哪个 broker,容器化部署都是最稳妥的起步方式,隔离干净、回滚也方便。
Mosquitto 的容器部署通常是这样的:
docker run -d \ --name mosquitto \ -p 1883:1883 \ -p 9001:9001 \ -v /opt/mosquitto/config:/mosquitto/config \ eclipse-mosquitto:2EMQX 的启动命令因为服务多,端口要映射一堆:
docker run -d \ --name emqx \ -p 1883:1883 \ -p 8883:8883 \ -p 8083:8083 \ -p 8084:8084 \ -p 18083:18083 \ emqx/emqx:5.8国产 broker 如果以二进制方式分发,更建议直接跑在 systemd 下,方便做成开机自启服务和日志轮转。初期建议只在测试环境起一个节点,先验证连接路径通不通,不要一上来就迁移生产流量。
部署完第一件事不是马上做业务测试,而是检查默认端口和匿名访问是否关闭。很多开源 broker 初始配置都允许匿名连接,这在测试环境无所谓,一旦暴露到公网就是事故。
4.2 功能对齐验证:连接、QoS、遗嘱、保留消息一个不能少
迁移过程中我强烈建议不要直接用业务代码去试,先用标准客户端工具做协议级验证,把基础能力逐项打钩。
MQTTX 和 mosquitto_pub / mosquitto_sub 是最趁手的工具。测试项建议覆盖:
- 匿名连接是否被正确拒绝,合法账号能否通过;
- QoS 0/1/2 三种级别下,消息到达顺序和去重行为是否符合预期;
- 保留消息是否在 broker 重启后还能读到;
- 遗嘱消息在客户端异常断网时能否按预期发布;
- clientId 冲突时新老连接谁会被踢掉。
MQTT 版本差异也是一个容易翻车的地方。老设备可能还在用 MQTT 3.1(协议版本号 3,非 3.1.1),新 broker 如果只监听 3.1.1 和 5.0,老设备直接握手失败。测试阶段一定要拿一批真实的存量设备来连,而不是只用最新 SDK。
4.3 安全与转发补齐:TLS、认证和规则链的替代方案
EMQX 用户迁移时最痛的通常是规则引擎。以前在 EMQX 上配一条规则,就能把某个主题的数据直接写入 MySQL 或 Kafka,换成国产 broker 以后,如果它没有规则引擎,这条链路就得自己搭。
我见过一个工业项目就这么处理的:保留 EMQX 开源版作为边缘接入,数据通过内部桥接协议转发到自研的 Go 服务,由 Go 服务负责数据清洗入库。迁移后虽然少了一个现成组件,但逻辑反而更透明了,排错也更容易。
认证链路的迁移要仔细对一遍。EMQX 支持内置数据库认证、HTTP 认证、JWT 认证,切换后你得确保新 broker 至少有一种认证方式能和现网对接。我最推荐的还是 HTTP 认证:broker 在客户端连接时回调你的认证服务,返回 accept 或 deny。这种方式不依赖 broker 内置的用户体系,迁移时改动最小。如果新 broker 不支持 HTTP 认证,那就只能提前把用户数据导入到它的内置存储里。
TLS 证书这一层基本没问题,因为 MQTT over TLS 是标准机制,broker 只管加载证书,客户端管验证。换 broker 只需要把证书文件迁过去,保持域名不变,客户端甚至不用改配置。注意私钥文件权限要锁死,别用chmod 777。
4.4 压测与灰度切换:数据层面怎么平滑迁移
功能验证完不等于可以生产,压测是不可跳过的一步。压测前先把阈值定下来,不然测完也不知道结果算好算坏。
通常我会分三档:
- 连接数压测:模拟设备分批上线,观察 broker 的连接数曲线、内存占用和 TCP 连接回收情况;
- 消息吞吐压测:QoS 1 场景下,固定频率发布消息,看处理延迟是否持续走高;
- 长稳测试:至少跑 48 小时,观测内存泄漏和句柄数异常。短时间压测看不出问题,跑两天才现原形的情况我见过太多次。
压测通过之后,灰度切换建议按主题前缀来做,而不是一次性把全部设备切换过去。比如先切 test/* 运维相关主题,再切一批真实设备,观察两套 broker 并行期间的数据一致性。切换步骤上,优先改设备端的 broker 地址;如果设备端不好改,再考虑在网关或负载均衡层做转发。
注意:如果使用了持久会话和离线消息,切换期间尽量拉长两套系统并行的时间。MQTT 的离线消息只存在旧 broker 上,一旦切过去,离线期间的消息可能全部丢。最好的做法是错开业务低峰期,先让所有设备在线并确认连接稳定,再关闭旧 broker。
5. 常见问题与排查技巧实录
5.1 协议尾巴差异:QoS 语义、返回码和遗嘱行为
替换之后最容易踩的第一个坑就是 QoS 语义差异。协议标准写得很清楚,但落地实现千差万别。最典型的是 QoS 2 的消息去重,有些国产实现会在极端场景下重复投递消息,有些则干脆把 QoS 2 降级成 QoS 1。
我遇到过一个现场:老平台用的是 EMQX 时 QoS 2 消息不会重复,换成自研 broker 后发现下游数据库出现重复记录,查了半天才定位到是 QoS 2 的 PUBREC/PUBREL 流程没按规范走。排查这类问题,最快的办法不是抓业务日志,而是直接在 broker 上抓包,对比 MQTT 报文交互是否符合协议。把连接关掉,逐个确认 PUBLISH、PUBACK、PUBREC、PUBREL、PUBCOMP 的报文序列,问题基本一眼可见。
遗嘱消息的触发条件也要单独验证。有的 broker 依赖 TCP 层断开来感知掉线,却对 MQTT 层的 keepalive 超时处理得很粗糙。结果就是设备已断电,遗嘱消息延迟很久才发出来,业务侧判定逻辑直接错乱。这个测试必须在真实网络环境下做,关掉 Wi-Fi、拔网线、拔电源,三种情况分别验证。
5.2 生态依赖陷阱:规则引擎和监控告警要提前找平替
很多团队迁移到一半才发现问题不在 broker 本身,而是周边生态空了一截。EMQX 的 Dashboard 里能看连接数、订阅数、消息速率,自带告警规则,换到新的国产 broker,如果它只有/metrics接口,那监控就得自己搭。
我建议迁移前就把监控方案定好:新 broker 如果能暴露 Prometheus 指标,直接用 Prometheus 加 Grafana 接管;如果只有系统日志,那就用 filebeat 把日志采集进 ELK,再在 Kibana 里做告警。别等上线了才发现没有监控可用,生产裸奔是很恐怖的事。
数据转发也一样。EMQX 规则引擎没了,就用 Node-RED 甚至一段简单的消费程序补齐。Node-RED 做 OPC UA 转 MQTT 本身就很常见,你完全可以让它同时订阅 MQTT 主题,再转发到数据库或 Kafka。逻辑虽然多一跳,但灵活性反而更高。
5.3 稳定性与社区风险:不能只看 Star 数
选国产开源项目时最容易犯的错误是看 GitHub Star 数选型。Star 多只能说明关注度高,不说明项目维护健康。
我自己的判断维度包括:最近一次 commit 是什么时候;Issue 响应速度如何;是否有明确的版本发布节奏;核心维护者是个人还是公司。个人项目哪怕代码写得再好,用在生产环境也要非常谨慎。一旦核心维护者不再更新,你面对的将是一个没人修 bug、漏洞无人响应的黑盒。
还有个更隐蔽的风险叫依赖风险。broker 本身是 Apache 2.0,但它依赖的某个底层库可能是 GPL。由于 MQTT broker 通常是独立进程,与业务代码通过 TCP 通信,这种动态隔离较少触发 GPL 传染,但如果你把 broker 作为库嵌入到自己的程序里分发,情况就不同了。上线前用开源扫描工具把所有依赖过一遍,把许可证清单归档,这是我能给的最实在的合规建议。
一些实际体会
我自己做技术选型有个习惯:先假设所有方案都有坑,列一个风险清单,逐项去验证,而不是先入为主地觉得某个方案好。替换 MQTT broker 这件事,技术上远没有想象中复杂,协议是标准化的,客户端是无感的,真正的复杂度全藏在版权义务、生态依赖和运维细节里。
如果要给一个最小起步建议,我会说:先在测试环境部署一个国产 broker,把基础协议测试跑一遍,重点验证 QoS、遗嘱、保留消息和 clientId 冲突策略这四个行为,再决定要不要推进到生产。这几个点踩不住,后面的性能优化、集群扩展都是空中楼阁。
比如 QoS 2 的消息去重,很多 broker 在低并发下表现正常,并发一上来就出问题。这类问题测试环境未必复现得了,所以我的做法是提前准备一个公网测试 topic,把将要接入生产环境的老设备先连到新 broker 上跑几天,观察实际消息链路是否完整。这比压测工具跑出来的数据有说服力得多。迁移那天,给所有设备提前留好配置回滚的方案,新 broker 出问题能一键切回旧 broker,这件事做到位了,剩下的交给时间。