十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

MQTT国产化替代:协议栈选型与许可证合规避坑指南

MQTT国产化替代:协议栈选型与许可证合规避坑指南 MQTT 这几年在国内几乎成了物联网设备接入的事实标准。不管是工业网关、充电桩还是智能家居 App只要设备端和云端要通信十有八九会碰到这个轻量级发布订阅协议。我在不少项目里都遇到过同一个问题项目里 Mosquitto、EMQX 用得很顺但一旦遇到公司国产化技术栈改造或者合规评审要求盘点开源组件马上就会被问“能不能换成国产 MQTT 协议栈换哪个换了之后开源版权和商用风险怎么算” 这篇文章就把我实际验证过的几条替代路线、Mosquitto / EMQX 的许可证差异以及迁移实操中的坑完整写出来给正在做选型或者被合规卡住的团队做个参考。1. 先把“替代对象”拆清楚MQTT 协议栈的边界1.1 服务端、客户端和协议本身别混为一谈很多朋友一上来就说“我要找个国产 MQTT 协议栈替代 Mosquitto / EMQX”但这里有个概念要先理清楚MQTT 本身是 OASIS 维护的开放标准协议它不归任何一家公司所有任何语言、任何厂商都可以参考规范实现一套。所以“替代”的对象从来不是协议而是协议的具体实现。从部署形态上看MQTT 相关代码通常分三类消息代理broker也就是服务端负责接收客户端连接、处理订阅发布、保存离线消息。Mosquitto 和 EMQX 都属于这一类。客户端 SDK运行在设备、手机、后台服务里的协议栈负责连上 broker、发消息、收消息。比如 Paho、mqtt.js、各种嵌入式 C 库。桥接/网关组件把其他协议转成 MQTT或者把 broker 之间的数据打通。“协议栈”这个词在嵌入式圈子里经常指客户端侧的完整链路比如 lwIP MQTT client有人在 STM32 上做联网透传时会把这一整套叫作协议栈。所以做替代之前先判断你要换的是哪一层。如果只是嵌入式设备上的联网模块换的是客户端 SDK如果是服务集群换的是 broker如果只是“把东西搬到国产云 IoT 平台”那连代码可能都不用改。1.2 国产化替代通常有四条路线我在实际项目里总结下来国产化替代并不是只有“找一个国产 broker 装上”这一条路至少可以分成四种:换 broker把 Mosquitto / EMQX 换成国产开源的 NanoMQ、Jmqtt或者继续用 EMQX它本身就是国内团队主导的开源项目。这个方案最直接对客户端透明。换客户端 SDK嵌入式场景下把 Paho Embedded-C、Mosquitto 客户端库等换成 TencentOS-tiny MQTT、华为 LiteOS MQTT、RT-Thread 软件包等。全链路自研/定制对协议有特殊要求、需要深度裁剪或安全加固的团队会选择基于协议规范自研。成本高但可掌控性最强。使用商业托管服务阿里云 IoT、华为云 IoTDA、腾讯云 IoT 等平台同时提供 MQTT 接入端点不自己部署 broker也就无所谓 broker 替代。这四条路线不是互斥的。边缘网关用 NanoMQ上层应用继续用商用的云 MQTT中间做桥接这是很常见的一种组合。选择的关键其实不在“国产”这两个字而在于许可证合规、功能覆盖长期运维成本。2. 开源许可证对比决定风险的第一层因素2.1 Mosquitto 的 EPL/EDL 双许可拆解Mosquitto 是 Eclipse 基金会项目采用 EPL-2.0Eclipse Public License 2.0和 EDL-1.0Eclipse Distribution License 1.0双许可。权利用户选择其中一个来遵守。这两个许可证的差别直接决定你拿它去二次开发后的义务。EPL-2.0 属于弱 copyleft 协议。它不要求你把整个系统开源但如果你修改了 Mosquitto 源代码并且把修改后的版本作为独立产品分发给别人那么你必须提供修改部分的源码和授权说明。这个“分发distribution”是核心触发条件。如果 Mosquitto 只是跑在服务器内部为你的设备、SaaS 业务提供服务即使做了深度修改也不触发源码公开义务。这一点很多人搞混以为用了 GPL/EPL 就必须把业务代码全部公开其实不是。EDL-1.0 则是一个非常宽松的许可本质上和 BSD-3-Clause 基本一致允许修改、允许闭源、允许商用分发只需要保留版权声明和免责声明。所以如果你的产品需要把 Mosquitto 打包进商业网关对外出货优先选择 EDL-1.0 授权并在产品文档里保留版权声明即可。2.2 EMQX 的 Apache-2.0 和商业化边界EMQX 开源版采用 Apache-2.0 许可证属于宽松许可证里相当友好的一种。它允许自由使用、修改、商用、甚至把修改后的代码闭源再发布。但有两个条件必须满足保留原始版权声明、保留 NOTICE 文件。此外你不可以在修改后的产品里使用 EMQ 公司的商标去暗示这是官方出品。不过要注意EMQX 的“开源”和“商业”边界在 5.x 版本之后变得更复杂了。基础 broker、集群、规则引擎这些核心能力在 Apache-2.0 版本里都有但一部分面向企业场景的功能比如部分数据集成连接器、企业级 Dashboard 高级功能、多集群管理、K8s Operator 的一些高级特性只放在企业版/旗舰版里。也就是说你在做替代方案时必须按你实际用到的功能清单去确认如果团队用的是开源版覆盖不到的功能那就得把企业版订阅费用也纳入选型成本而不是天真地认为“开源就是永远免费”。另外EMQX 这个项目本身有一个很特殊的位置它由国内公司 EMQ杭州映云科技主导开发办公地点在国内社区也是中文友好。按照很多企业“国产化选型”的标准EMQX 本身就是国产开源项目。所以从合规角度说如果团队实在找不到其他替代继续用 EMQX 开源版也完全说得通关键是把功能边界和授权文档搞清楚。2.3 国产候选方案与许可证速查表这里我把自己调研过的几个国产方案放在一起方便对照。需要强调开源项目的许可证可能随版本调整具体以官方仓库的 LICENSE 文件为准。方案定位许可证说明NanoMQ边缘/嵌入式 brokerC 语言实现MIT以仓库当前声明为准EMQ 公司出品轻量适合网关、边缘盒子JmqttJava 实现的服务端 brokerApache-2.0以仓库当前声明为准可直接嵌入 Java 应用适合 RuoYi/Spring Boot 团队TencentOS-tiny MQTT嵌入式客户端协议栈MIT以仓库当前声明为准配套腾讯物联网生态适合 MCULiteOS MQTT嵌入式客户端协议栈BSD-3-Clause以仓库声明为准华为 LiteOS 自带组件适合 LiteOS 华为云场景RT-Thread MQTT 软件包嵌入式客户端协议栈以软件包仓库 LICENSE 为准RT-Thread 生态基于 Paho 移植需逐项确认EMQX 开源版分布式 brokerApache-2.0国内团队主导社区成熟Paho MQTT客户端/统一客户端 SDK多平台EPL-2.0 / EDL-1.0Eclipse 官方许可证与 Mosquitto 同源一个容易被忽略的点“国产”不等于可以随意使用。TencentOS-tiny、LiteOS、Jmqtt 这些项目一样遵守开源许可证条款用了就要保留版权声明。如果二次开发并对外分发也要按各自许可证要求履行义务。2.4 商用前必须做的一次合规自查很多团队在做完技术选型后才意识到许可证问题往往为了赶工期就“先上再说”。我建议无论选择哪个替代方案上线前都要做一次系统性的合规自查至少覆盖以下几个方面依赖清单把部署产物、客户端 SDK、网关程序的所有第三方库列出来挨个确认许可证类型。修改状态你是否修改过这些库的源码修改了哪些文件能否导出补丁或 diff分发方式代码是否随硬件产品、安装包一起发给外部还是只在你自己的服务器上跑这决定 copyleft 义务是否触发。保留文件编译产物里是否包含了 LICENSE、NOTICE、Copyright 声明很多团队换了个 jar 包就把 NOTICE 丢了这在 Apache-2.0 项目里属于违规。SaaS 边界如果你的产品是“帮客户私有化部署一套系统”这种场景很容易被误判为内部使用。实际上如果把修改后的 broker 作为客户交付物的一部分依然属于分发行为。为了提高检查效率可以在 CI 里加一个依赖扫描步骤用 ScanCode Toolkit 或 FOSSA 这类工具自动识别依赖许可证把检查结果作为发布的前置门禁。比人工翻代码高效得多。当然涉及重大商业决策时还是建议把扫描结果发给专业的律所或法务做最终判断开源许可证的法律细节很多工程师自己能识别常见风险但代替不了正式的合规意见。3. 替代路径实操嵌入式、边缘网关和服务端3.1 嵌入式场景MCU 上移植国产 MQTT 客户端嵌入式场景下的替代重点在客户端协议栈选型。据我了解国内 MCU 项目中用得比较多的是 TencentOS-tiny 的 MQTT 组件、华为 LiteOS MQTT 组件以及 RT-Thread 软件包里的 MQTT 组件。这些方案在代码层面做了很多裁剪比较适配资源受限的芯片。以 STM32 lwIP 为例一个最小可用方案只需要五步网络栈就绪确保 lwIP 能正常 ping 通 broker 地址能解析域名或直接使用 IP。引入 MQTT 客户端源码从 TencentOS-tiny 或 LiteOS 仓库拉取 mqtt 组件加入工程编译。很多国产 IDE如 RT-Thread Studio、华为 LiteOS Studio已经内置了示例工程可以直接使用。配置连接参数核心参数包括 Broker 地址IP 或域名、端口默认 1883、ClientId每个设备唯一、Username/Password如果 broker 开启了认证、KeepAlive 时间一般 60 秒、CleanSession断线后是否需要恢复会话。实现订阅与发布回调在收到消息的回调函数里解析 topic 和 payload。有些 MCU SDK 要求你自己维护一个环形缓冲区或者消息队列避免在中断上下文里直接处理协议栈数据。加入重连逻辑MQTT 断线很常见特别是 4G 模块信号不稳的时候。常见做法是检测到断线后延时 5 秒、10 秒递增重连最多 5 次后重置为初始间隔同时利用 Last Will 消息告诉云端设备离线了。这里有个参数容易踩坑KeepAlive 设太短会导致低功耗设备频繁唤醒发心跳设太长会导致 broker 无法快速感知设备离线。对于电池供电的传感器节点我们项目里一般设置 120 秒以上对于工业网关这类持续供电设备60 秒比较合适。另外如果设备用 4G 模块比如 EC20通过 AT 指令拨号MQTT 客户端还要考虑模块自身的网络注册状态这部分网络通断往往不在 MQTT 协议栈层面处理。3.2 边缘网关场景用 NanoMQ / Jmqtt 替换 Mosquitto边缘网关场景是我最常被问到的以前网关内部跑一个 Mosquitto设备、协议转换服务、上层业务全都通过它互连现在想换成国产方案。这里的首选我会推荐 NanoMQ。NanoMQ 是 C 语言实现启动快、内存占用小非常适合放在边缘设备里。Docker 方式部署只需要一行命令docker run -d -p 1883:1883 -p 8083:8083 emqx/nanomq:latest不过边缘网关通常不是 Docker 环境更常见的做法是直接编译二进制。从 GitHub 拉取源码执行mkdir build cd build cmake -G Ninja .. ninja编译后得到 nanomq 可执行文件配合一个 etc/nanomq.conf 配置文件启动即可。核心配置项里listener 的端口地址、认证方式、WebSocket 开关、桥接规则这几项要重点关注不用上来就调性能参数。我惯用的一个最小配置写法是这样listener.tcp { bind 0.0.0.0:1883 } listener.ws { bind 0.0.0.0:8083 } # 认证关闭匿名访问只允许账号密码登录 basic_auth { no_match deny } auth.username edge_user auth.password edge_password注意 NanoMQ 的配置语法在不同版本之间有变化用之前先对应官方文档确认。如果碰到老版本auth 部分的字段名可能不同。Jmqtt 则更适合 Java 技术栈团队。它可以作为一个普通 Java 进程独立运行也可以直接以库的形式集成到 Spring Boot / RuoYi 这类系统里。Jmqtt 在 1.x 版本提供了集群能力比单机运行的 Mosquitto 在扩展性上更灵活。对你的业务系统来说这意味着不用单独维护一个 broker 服务直接在应用里启动 Paho 风格的 server设备连接进来之后业务代码就近处理即可。从 Mosquitto 迁移到 NanoMQ / Jmqtt配置对照大致如下功能Mosquittomosquitto.confNanoMQ / Jmqtt 对应项监听端口listener 1883listener.tcp.bind / server.port匿名访问allow_anonymous true/falsebasic_auth.no_match allow/deny用户名密码文件password_file /etc/mosquitto/passwdbasic_auth 的用户名密码或 HTTP 认证WebSocket 监听listener 8083 protocol websocketslistener.ws.bind持久化persistent true对应数据库/持久化路径配置桥接bridge mosquitto-bridge.confNanoMQ bridge 配置块这里最容易出错的是 ACL 默认行为。Mosquitto 的默认配置如果没写 allow_anonymous 和 password_file是允许匿名访问的而 NanoMQ 默认会拒绝未认证连接不同版本行为不同。所以迁移之后一定要先验证“未带账号密码的客户端是否还能连接”。很多设备端程序从来没传过密码迁移到新 broker 后第一天就集体掉线基本都是这个原因。3.3 服务端集中部署为什么 EMQX 开源版常是“国产替代”答案如果你的业务量到了“需要集群、需要数据集成、需要可视化 Dashboard”这个阶段建议直接评估 EMQX 开源版。这里有个很多人没意识到的事实EMQX 是国内团队主导的项目很多国产化评审中它本身就是合规候选而对比 Mosquitto 这类单机 brokerEMQX 在吞吐量、集群、多协议支持上的优势非常明显。从 Mosquitto 迁到 EMQX 的步骤不复杂部署Docker 方式部署最省事执行docker run -d --name emqx -p 1883:1883 -p 8083:8083 -p 8883:8883 -p 8084:8084 -p 18083:18083 emqx/emqx:5.x本机打开http://host:18083进入 Dashboard默认账号 admin/public。配置认证Dashboard 里的“访问控制 - 认证”可以添加用户名密码、JWT、HTTP 认证。从 Mosquitto 迁移时建议把原来的 password_file 导出为 CSV然后通过 Dashboard 或 HTTP API 批量导入。配置 ACLEMQX 的授权规则语义比 Mosquitto 更丰富。Mosquitto 里的每主题 ACL 规则在 EMQX 里可以通过内置数据库或 SQL 实现。验证功能注意检查 retained 消息、遗嘱消息、QoS 2 行为。不同 broker 对 session 恢复的持久化方式不同尽量用真实客户端做一轮完整回归。接入数据中心EMQX 的规则引擎可以把 MQTT 消息直接写入 MySQL、PostgreSQL、Kafka、ClickHouse 等系统。原来你用 Mosquitto 还需要额外开发一个消费程序用 EMQX 可以减少这条链路。但也要泼一盆冷水如果只是几十台设备的小场景、只想要一个轻量 brokerEMQX 反而是过度设计。它默认开启很多功能内存占用比 Mosquitto、NanoMQ 高不少运维面也更大。选型要根据体量来不要盲目追“强大的”。4. 验证、压测与运维迁移避坑4.1 协议兼容性与客户端矩阵替换 broker 最怕的不是功能缺失而是“老的客户端连不上”。MQTT 版本有 3.1、3.1.1、5.0 的差异很多老设备只有 MQTT 3.1 的实现同时不同语言的 SDK 底层实现细节也不同。我们在更换 broker 后总是会按客户端矩阵做一轮真实设备测试而不是只用一个测试工具连一下就算完。常用的客户端样本包括JavaEclipse Paho JavaPythonpaho-mqtt前端mqtt.jsvue3 项目里经常直接 websocket 连 broker嵌入式paho embedded-c、TencentOS-tiny MQTT工业软件KepwareKepServerEX 的 MQTT 插件、MCGS 组态触摸屏、Node-RED通过 MQTT out 节点测试项至少覆盖连接鉴权、普通订阅发布、QoS 0/1/2、retained 消息、Last Will、CleanSession 为 0 时的会话恢复、断线重连、TLS 连接。如果客户端走的是 8083 WebSocket 端口还得确认 WebSocket 路径是否正确。很多前端 mqtt.js 默认连接路径是/mqtt而部分 broker 默认路径为空迁移后很容易在这里断掉。4.2 性能压测的简单有效方法做替代选型时性能测试不可少但不需要一上来就堆集群。我建议先用小规模压测验证单机能力看它能否承载预期业务峰值的 N 倍。压测工具可以直接用 EMQ 出品的 emqtt-bench它支持指定连接数、消息数量、QoS、payload 大小# 模拟 1000 个客户端每个客户端订阅 benchmark/topic emqtt_bench sub -c 1000 -t benchmark/topic -h broker_ip -p 1883 # 模拟 100 个客户端持续 60 秒以 QoS 1 发布 256 字节 payload emqtt_bench pub -c 100 -t benchmark/topic -h broker_ip -p 1883 -q 1 -s 256 -x 60压测过程中要重点看五个维度CPU 使用率、内存占用、打开文件描述符数量、TCP 连接数、消息积压情况。如果部署的是 Jmqtt还要额外关注 JVM 的 GC 频率和堆内存如果是 NanoMQ 这种 C 实现则要关注进程的连接数上限以及系统层ulimit -n是否调大。另外压测之前记得调整内核参数否则 broker 程序本身没问题系统 socket 队列先丢包了sysctl -w net.core.somaxconn1024 sysctl -w net.ipv4.tcp_max_syn_backlog1024 sysctl -w fs.file-max65535这里有个很容易犯的错压测机和 broker 放同一台机器的不同 Docker 容器里网络栈干扰严重数据不可信。我习惯用独立机器或者至少在 host 模式下压测避免经过 Docker 桥接网络带来的额外延迟和丢包。4.3 移植到生产时容易踩的运维坑服务端 broker 部署看起来简单打开端口就能跑但到生产环境一上量就各种问题。以下这几个坑是我实际遇到过、也见别人踩过的端口忘了全开接入层只开了 1883没开 8883TLS、8083WebSocket、8084WebSocketTLS前端和加密设备全部掉线。** systemd 单元没写对**Mosquitto 默认作为系统服务安装但手写编译的 NanoMQ 往往需要自己写 systemd 文件。进程退出后不能自动拉起这是生产事故高发点。日志无轮转有些 broker 在调试模式下日志量巨大几天就能占满磁盘。需要配合 logrotate 按时切割日志。证书权限混乱TLS 证书私钥文件如果权限为 644部分 broker 会拒载或报警建议统一 600 权限并确保 broker 进程用户有读权限。存储目录不一致离线消息、会话、retained 消息如果放在临时目录重启就丢。要显式指定数据持久化目录并在更新版本前备份。生产环境还有一个建议为 broker 单独建一个系统用户不要用 root 跑。无论 NanoMQ 还是 Jmqtt最小权限原则都适用。否则如果 broker 对外暴露了一个漏洞攻击者拿到的是整台服务器的控制权。5. 常见问题与失败经验速查5.1 许可证上的几个高发误区关于开源许可证我见过太多被误导的处理方式这里把高发误区集中说一下。误区一开源软件不能用于商业。这句话只在特定条件下部分成立。Apache-2.0、MIT、BSD、EPL、EDL 都允许商用GPL 允许商用只是如果你分发修改后的代码需要开源修改部分的源码。不能笼统地说“开源 不能商用”。误区二用了 GPL/EPL 协议栈我的全部业务代码都必须开源。只要你的业务代码是独立进程、通过标准协议与 broker 通信比如通过 MQTT 客户端连接一般不会被传染。真正需要注意的只是“修改并分发”的场景。误区三用了国产开源项目等于有国产团队背书许可证随便用。开源许可证不看国籍只按其条款执行。你用了 MIT 项目就要保留版权声明你改了 Apache-2.0 项目就要保留 NOTICE这些义务不因项目是国产或国外而改变。误区四我改了代码但我不卖钱就不算分发。分发和营利无关。哪怕免费把固件、安装包发给第三方客户只要包含开源组件且修改过EPL/GPL 照样触发源码提供义务。误区五内部自用完全没有任何义务。如果是纯内部服务不对外分发通常不触发 copyleft但“内部”的范围很重要。如果集团子公司 A 用了子公司 B 也用但没有授权链可能仍存在合规风险。最稳妥的方式还是建立台账记录软件从哪来、协议是什么、有没有改动。5.2 迁移后行为不一致的排查迁移 broker 后经常出现“客户端连上了但消息收发不正常”的情况。我查过比较多的有三类第一类是 session 恢复异常。原来用 Mosquitto 的时候CleanSession0 的客户端断开再连能收到离线期间的 QoS 1 消息迁移到新 broker 后可能因为持久化开关没打开离线消息丢失。解决方法是在新 broker 配置里开启持久化并用一个测试客户端订阅 QoS 1 主题发消息后断开再重连验证。第二类是保留消息retained行为不一致。MQTT 协议规定broker 只会为每个 topic 保存最后一条 retained 消息。但有些 broker 在重启后会清空 retained 消息有些则持久化存储。如果你在迁移前没有把旧 broker 的 retained 消息导出迁移后所有新上线的设备可能都收不到设备的当前状态必须要求设备重新上报一次状态。第三类是路径和默认值不一致。像我们前面提到的Mosquitto 默认允许匿名NanoMQ 默认可能拒绝Mosquitto 对 clientId 为空字符的处理、对重复 clientId 的策略在目标 broker 上也可能不同。迁完以后建议用几台不同 SDK 的真机跑一个全量回归脚本把“连接 - 订阅 - 发布 - 断开 - 重连 - 收消息”走一遍比逐个查配置高效得多。5.3 团队内部推动替代的建议最后聊点组织层面的经验。很多项目卡住不是因为技术做不到而是没有人牵头把合规和选型标准定下来。我的建议是如果公司有国产化改造的目标尽早让基础架构团队统一做一次“MQTT 相关开源组件普查”把每个系统用到哪些 broker、客户端 SDK、桥接工具、对应的许可证、是否有二次修改全部记录成台账。然后在做完选型后把选型结果和许可证文件一起归档为《MQTT 协议栈选型与合规记录》。这个文档不需要很复杂几张表格就够了但它能在后续合规评审、客户尽调的时候帮你省掉大量翻代码的时间。在选型方案上除非你所在团队对某个候选方案有强烈的技术偏好否则按这个优先级走基本不会错嵌入式 MCU优先考虑 RT-Thread 或 LiteOS 内置的 MQTT 组件配合公司已有的芯片方案评估。边缘网关优先 NanoMQ尤其多设备接入、桥接到云平台的场景。Java 业务系统集成优先 Jmqtt嵌入进程内部署最轻。服务端大规模集中部署EMQX 开源版功能、性能、社区成熟度都经过验证本身就是国产项目。最后再分享一点个人体会我自己的踩坑经历是在一个商业网关项目里把 Mosquitto 改了端口和主题前缀直接嵌进产品对外出货后来合规评审才发现 EPL-2.0 下“对外分发修改后源码”是一条硬性义务好在我们的程序结构允许切换授权到 EDL-1.0补了一段版权声明并公开了修改部分的源码地址才算顺利过关。这件事给我最大的教训是选型当天先看 LICENSE 文件再谈功能和性能。国产 MQTT 协议栈的替代路线本身不复杂无非是 NanoMQ、Jmqtt、TencentOS-tiny、LiteOS、EMQX 这几个候选里做组合但“哪个环节有风险、哪个环节要保留文件”这个问题应该在写第一行代码之前就盘清楚。合规不是束缚它其实是帮你把技术债提前还掉。
返回列表