🔧 丁丁深度评测系列 · 第6篇(收官)

EMQX 深度评测

💡 工业 MQTT 服务器怎么选?百万级设备并发连接该用什么?

全球市场份额60%+的开源分布式MQTT消息服务器,丁丁实战24个月,4个项目验证。Erlang/OTP开发,单机100万+连接,10万+消息/秒,延迟<1ms,分布式集群亿级连接,规则引擎+20+数据集成,云原生友好。但也踩了5个大坑——规则引擎SQL有坑、QoS 1消息重复、集群脑裂、4.x升5.x不兼容、Linux端口耗尽,这篇评测全说透。

版本5.x
分类分布式MQTT消息服务器
协议Apache 2.0
丁丁评分9.0/10
实战时长24个月
🎯 丁丁一句话结论

生产环境做工业物联网消息中枢——设备量大、要高可用集群、要规则引擎自动入库,EMQX 是开源 MQTT broker 的首选(9.0分);只是边缘网关本地少量设备转发,Mosquitto 更轻;不采 PLC、只做 AMQP 复杂路由或流处理,选 RabbitMQ / Kafka。

01 软件定位与适用场景

EMQX是什么:EMQ(映云科技)旗下的开源分布式MQTT消息服务器,用Erlang/OTP开发,全球开源MQTT broker市场份额领先(约60%+)。单机支持100万+连接,10万+消息/秒,延迟<1ms;分布式集群支持亿级设备连接,自动故障转移,高可用。内置规则引擎(SQL-like语法,数据过滤/转换/聚合)和20+数据集成(MySQL/PostgreSQL/TDengine/InfluxDB/MongoDB/Redis/Kafka/Webhook等)。云原生架构(Docker/K8s Operator/Helm),是工业物联网、车联网、智能家居、智慧城市等场景的消息中间件首选。与Neuron同属EMQ技术栈,Neuron采集+EMQX消息+TDengine存储+Grafana展示是工业物联网全栈最佳实践。

核心设计哲学:①"高可用"——Erlang/OTP的高并发+分布式集群+自动故障转移,电信级可靠性;②"高性能"——单机100万连接,10万消息/秒,延迟<1ms,为IoT海量连接设计;③"云原生"——Docker/K8s/Operator/Helm,适合云原生部署和弹性伸缩;④"万物互联"——MQTT 3.1/3.1.1/5.0全协议支持,QoS 0/1/2,保留消息,遗嘱消息,会话持久化,适合各种IoT设备;⑤"数据集成"——规则引擎+20+连接器,消息可以直接写入数据库/发HTTP/转发Kafka,不用自己写消费端。

✅
适用场景
  • 工业物联网(设备数据采集/远程运维/预测性维护)
  • 大规模IoT平台(>1万设备,需要集群/高可用)
  • 车联网(T-Box/车机通信/车辆远程控制)
  • 智能家居(设备控制/状态上报/场景联动)
  • 智慧城市(传感器网络/环境监测/智能照明)
  • 实时消息推送(App/小程序/网页实时通知)
  • 微服务间异步通信(事件驱动架构/解耦)
  • 边缘计算(边缘消息转发/边缘规则引擎)
❌
不适用场景
  • 不需要消息队列的简单系统(直接HTTP调用就行,增加复杂度)
  • 超小系统(<10设备)——用Mosquitto更轻量,EMQX有点重
  • 需要复杂消息路由/编排(主题交换/死信队列/延迟队列)——用RabbitMQ
  • 需要事务性消息(分布式事务/消息不丢不重且有序)——用RabbitMQ或RocketMQ
  • 大数据/日志/流处理(极高吞吐量/事件溯源/批处理)——用Kafka
  • 需要JMS标准(Java消息服务)——用ActiveMQ/RocketMQ
  • 对Erlang运维不熟悉且没有企业版支持——出问题可能搞不定
  • 需要消息持久化到文件系统——EMQX消息默认内存,持久化需要企业版或外部数据库

02 丁丁的实战体验

👨‍🔧
丁丁智造
20年工业自动化全栈工程师 · 从EMQX 4.x用到5.x
9.0
综合评分

用了多久:24个月(2024年10月开始,从EMQX 4.4升级到5.7,经历了5.x大版本重构)

用在哪些项目:

  • 设备远程运维(200+设备):20个工厂,Neuron边缘采集→EMQX消息中转→TDengine存储→Grafana远程监控,EMQX是核心消息总线
  • 30台冲床监控:ThingsGateway采集→EMQX→TDengine→Grafana,EMQX做消息解耦(采集层和存储层分离)
  • 安灯系统:异常告警通过EMQX实时推送到车间大屏和管理人员手机,EMQX做实时消息推送
  • 条码追溯:扫码数据MQTT上报→EMQX规则引擎→写入MySQL,EMQX+规则引擎省去了写消费端的工作

整体感受:EMQX确实是MQTT broker的首选——性能极强(单机100万连接无压力,我们最多用到20万连接,CPU才40%)、稳定性极高(生产环境连续运行半年不重启,没出过一次故障)、功能丰富(规则引擎/数据集成/管理控制台都很好用)、云原生友好(Docker/K8s部署方便)、与Neuron无缝集成(同一家公司,Neuron+EMQX+TDengine全栈方案很成熟)。Dashboard管理界面友好,配置简单,文档完善(中文文档很全,对国内开发者友好)。社区活跃(GitHub 13k+ Star,国内用户多,问题响应快)。

但也有需要注意的地方:规则引擎的SQL语法有学习成本(不是标准SQL,有特殊函数)、QoS 1消息会重复(消费端必须做去重)、集群部署需要注意脑裂问题(要开autoheal+奇数节点)、4.x升级5.x配置不兼容(大版本升级要谨慎)、大量连接时需要调优Linux内核参数(文件句柄/端口/连接跟踪表)。我的经验是:EMQX适合做"消息传输层",是工业物联网架构的核心基础设施——Neuron/ThingsGateway做采集层,EMQX做消息层,TDengine做存储层,Grafana做展示层,Node-RED做业务流程层,分层架构各司其职,EMQX在中间做消息总线,解耦上下游,是整个架构的"咽喉"。EMQX的评分我给9.0(6款里最高),因为它确实是最成熟、最稳定、最不可或缺的——其他5款都可以有替代,但EMQX在MQTT消息层几乎没有对手(大规模场景下)。

👍 优点

  • 全球市场份额领先——开源MQTT broker市场占有率约60%+,社区最大最活跃
  • 性能极强——Erlang/OTP开发,单机100万+连接,10万+消息/秒,延迟<1ms
  • 分布式集群——多节点自动发现,水平扩展,单集群支持亿级设备连接
  • 高可用——自动故障转移,会话持久化,消息队列,生产环境连续运行半年不重启
  • 规则引擎强大——SQL-like语法,数据过滤/转换/聚合,内置20+数据集成
  • 云原生友好——Docker/K8s Operator/Helm Chart,适合云原生部署和弹性伸缩
  • 与Neuron无缝集成——同一家公司(EMQ),Neuron采集+EMQX消息+TDengine存储全栈
  • 管理控制台友好——Dashboard可视化监控连接/订阅/主题/规则,REST API完整

👎 缺点

  • 规则引擎SQL语法有学习成本——不是标准SQL,有特殊函数和语法,初期写的规则不生效
  • MQTT QoS 1消息重复——QoS 1是"至少一次",网络抖动时重复投递,消费端必须做去重
  • 集群脑裂问题——网络分区时集群分裂,两个节点都认为自己是主,需正确配置防脑裂
  • 4.x升级5.x配置不兼容——配置文件格式大变,升级后配置全失效,需要重新配置
  • 大量连接时Linux端口耗尽——单机10万+连接时,默认端口范围不够,需要调大内核参数
  • Erlang虚拟机调优需要经验——VM参数/进程数/缓冲区配置不当会影响性能
  • 开源版缺少部分企业功能——数据持久化原生支持/LDAP集成/专业报表在企业版
  • 5.x的Dashboard与4.x差异大——老用户需要重新学习,部分功能位置变了

03 核心功能演示

📡
MQTT全协议支持
MQTT 3.1/3.1.1/5.0,QoS 0/1/2,高并发低延迟
MQTT 3.1 / 3.1.1 / 5.0  全版本支持
QoS 0: 最多一次(可能丢,性能最高)
QoS 1: 至少一次(不丢,可能重复,最常用)
QoS 2: 恰好一次(不丢不重,性能开销大)
保留消息(Retained): 新订阅者立即收到最新消息
遗嘱消息(Will): 客户端异常断开时自动发布
会话持久化(Session): 客户端离线时缓存消息
共享订阅(Shared Subscription): 多客户端负载均衡消费
TCP: 1883  WebSocket: 8083  SSL/TLS: 8883
🔄
分布式集群
多节点自动发现,水平扩展,亿级连接
基于Erlang分布式协议
多节点自动发现(static/dns/etcd/k8s)
水平扩展,单集群亿级连接
自动故障转移,客户端自动重连
会话/路由/订阅自动同步
autoheal: 网络分区恢复后自动愈合
奇数节点: 3/5/7节点,防脑裂
负载均衡: Nginx/HAProxy/NLB分发连接
⚙️
规则引擎
SQL-like语法,数据过滤/转换/聚合,20+动作
规则引擎三段式:
SQL(SELECT+FROM+WHERE)
  → 动作(Action)
  → 否则动作(Else Action,可选)

SQL示例:
SELECT payload.temperature as temp, clientid
FROM "t/device/+/data"
WHERE payload.temperature > 80

内置变量: clientid/topic/payload/username
常用动作: MySQL/PostgreSQL/TDengine/InfluxDB
        MongoDB/Redis/Kafka/HTTP/republish
🔐
认证授权
内置/JWT/外部数据库认证,ACL权限控制
认证方式:
内置数据库: 用户名密码存在EMQX
JWT: Token认证,适合App/小程序
MySQL/PostgreSQL/Redis: 外部数据库
LDAP: 企业LDAP认证(企业版)
HTTP API: 调用外部接口认证

授权(ACL):
内置ACL: 配置发布/订阅权限
默认策略: deny(白名单,推荐)
每个设备用独立用户名密码
生产环境开启TLS加密

04 5个真实踩坑(每个都花了时间和钱)

坑 01 规则引擎SQL语法有坑——不是标准SQL,有特殊函数和语法,初期写的规则要么不触发,要么报错,数据写不进TDengine
根因分析: EMQX的规则引擎用的是"类SQL"语法,但不是标准SQL——它有自己的特殊函数(如payload.x、clientid、topic等内置变量)、特殊语法(如FOREACH、CASE WHEN的用法和标准SQL不同)、以及特定的动作(republish、console、data_to_tdengine等)。初期接触时,很容易用标准SQL的思维去写规则,结果要么语法报错,要么规则不触发(因为WHERE条件写错了),要么数据格式不对(因为SELECT的字段名和数据库表字段不匹配)。设备远程运维项目初期,写了一个"把设备数据写入TDengine"的规则,用了标准SQL的INSERT语法,结果一直报错——EMQX规则引擎不是用INSERT,而是用SELECT + 动作(Action),在动作里配置数据库连接和表映射。还有一个坑:EMQX的payload默认是JSON字符串,需要用payload.field来引用字段,但如果payload不是JSON(是二进制或纯文本),需要用解码函数(如base64_decode/hex_to_binary),初期不知道这个,导致非JSON payload的规则一直不触发
解决方案: 规则引擎的正确写法(5条经验):①先理解EMQX规则引擎的三段式——SQL(SELECT字段+FROM事件+WHERE条件)→ 动作(Action,如写入数据库/发HTTP/republish)→ 可选:否则动作(Else Action,条件不满足时执行),不是标准SQL的INSERT/UPDATE,不要用标准SQL思维;②用内置变量引用消息——SELECT payload.field1 as f1, clientid, topic FROM "t/#" WHERE payload.field1 > 100,payload是JSON对象,直接用.引用字段,clientid/topic/username是内置变量;③非JSON payload要先解码——如果payload是二进制(如Modbus数据),用SELECT base64_decode(payload) as raw_data,或者用FOREACH遍历数组,不要直接用payload.field;④先在Dashboard里测试——EMQX Dashboard的规则引擎有"SQL测试"功能,可以输入模拟的clientid/topic/payload,看SQL执行结果,确认字段和条件都对了再保存规则,不要直接写了就上线;⑤数据集成动作要配置表映射——写入TDengine/MySQL时,要在动作里配置"数据库连接"和"表名/字段映射",把SELECT出来的字段映射到数据库表的列,字段名可以不一样(在映射里配置对应关系)。按这套方法,设备远程运维项目的规则一次就写对了,数据正常写入TDengine,连续运行3个月无异常
坑 02 MQTT QoS 1消息重复——网络抖动时QoS 1消息重复投递,消费端没做去重,导致条码追溯项目的扫码数据重复入库,客户投诉数据不准
根因分析: MQTT协议的QoS(Quality of Service)有三个级别:QoS 0(最多一次,可能丢)、QoS 1(至少一次,可能重复)、QoS 2(恰好一次,不丢不重)。QoS 1是最常用的级别(保证不丢,但可能重复),因为QoS 2性能开销大(4次握手),大多数IoT场景用QoS 1。但QoS 1的"至少一次"意味着——如果网络抖动,发布方没收到确认(PUBACK),会重发消息,导致消费端收到重复消息。条码追溯项目初期,扫码数据用QoS 1上报,车间网络偶尔抖动(每天几次,每次几秒),导致每天有几十条扫码数据重复入库——同一次扫码被记录了2次,客户做产量统计时数据不准,投诉了。更坑的是,EMQX的会话持久化(Session Persistence)会在客户端离线时缓存消息,客户端重新上线后批量投递,如果客户端在网络抖动时断开重连,缓存的消息和新消息可能重复,进一步加剧重复问题。还有一个坑:EMQX的规则引擎写入数据库时,默认没有去重机制——如果规则触发了两次,就会写两次,需要在数据库层面做去重(唯一索引/INSERT IGNORE)
解决方案: QoS 1消息去重的4个方案:①消费端做幂等——每条消息带唯一ID(如扫码数据带timestamp+device_id+barcode的组合ID),消费端处理前先查这个ID是否已处理,已处理就跳过,这是最可靠的方案;②数据库层面做去重——表的唯一索引设为消息ID(或业务唯一键),用INSERT IGNORE或ON DUPLICATE KEY UPDATE,重复消息直接被数据库忽略,条码追溯项目用的就是这个方案(唯一索引=device_id+barcode+timestamp),重复数据直接被MySQL忽略;③如果业务允许重复——比如监控数据(温度/压力),重复一条影响不大,可以不做去重,用QoS 1保证不丢就行,不要为了完美去重增加复杂度;④关键业务用QoS 2——如果业务绝对不能重复(如支付/订单),用QoS 2(恰好一次),但QoS 2性能开销大(4次握手,吞吐量约为QoS 1的一半),只在关键路径用,不要所有消息都用QoS 2。条码追溯项目最后用了方案②(数据库唯一索引去重),重复数据问题彻底解决,客户满意。建议:项目设计时就考虑QoS级别和去重策略,不要做到一半才发现重复问题,被动补救
坑 03 集群脑裂问题——网络分区时集群分裂成两个独立集群,两个节点都认为自己是主,导致消息丢失或重复,设备远程运维项目的3节点集群出过一次脑裂,丢了约5分钟数据
根因分析: EMQX的分布式集群基于Erlang的分布式协议,多节点之间通过TCP连接通信,定期发送心跳检测节点状态。如果网络分区(如交换机故障、网络抖动、防火墙拦截),节点之间的连接断开,每个节点都认为其他节点"挂了",然后各自选举自己为"主节点",形成两个独立的集群——这就是"脑裂"(Split Brain)。脑裂发生后,两个集群都在独立处理消息,客户端可能连接到任意一个集群,导致消息路由混乱、消息丢失(发到A集群的消息B集群看不到)、消息重复(两个集群都处理同一条消息)、数据不一致。设备远程运维项目的3节点集群(EMQX 4.x),因为一次网络交换机故障(持续约5分钟),发生了脑裂——节点1和节点2在一个网段,节点3在另一个网段,节点3认为1和2挂了,自己选为主,1和2认为3挂了,继续运行。网络恢复后,EMQX自动合并集群,但合并过程中丢了约5分钟的数据(节点3上的消息没有同步到1和2)。更坑的是,EMQX 4.x的集群默认没有开启"脑裂防护"(autoheal),需要手动配置,初期不知道这个配置,脑裂发生后只能手动恢复
解决方案: 集群脑裂防护的5个措施:①开启autoheal(自动愈合)——EMQX配置里设置cluster.autoheal = true(5.x)或cluster.autoheal = on(4.x),网络分区恢复后EMQX会自动检测脑裂并重启少数派节点(保留多数派的数据),自动合并集群,这是最基本的防护;②配置节点发现方式——生产环境用static(静态节点列表)或dns(DNS A记录),不要用manual(手动加入),manual方式节点重启后需要手动重新加入,容易出问题;③奇数节点部署——集群节点数用奇数(3/5/7),不要用偶数(2/4/6),奇数节点在网络分区时能形成"多数派"(如3节点分区成2+1,2是多数派,1是少数派会被重启),偶数节点可能出现50/50分区,无法形成多数派;④网络层面做冗余——生产环境的集群节点之间用双网卡/链路聚合,避免单点网络故障导致分区,交换机用堆叠(Stack)或MLAG,避免交换机单点故障;⑤监控集群状态——用EMQX的REST API或Prometheus监控集群节点状态(emqx_cluster_nodes_running),节点数异常时立即告警(接入钉钉/邮件),脑裂发生后第一时间发现,手动干预(重启少数派节点)。设备远程运维项目最后开启了autoheal+3节点奇数部署+双网卡冗余+监控告警,连续运行1年再没出过脑裂问题。建议:生产环境集群部署时就配置好脑裂防护,不要等出了问题才补救,脑裂丢的数据可能是不可逆的
坑 04 4.x升级5.x配置不兼容——配置文件格式大变,升级后配置全失效(认证/规则/集成都没了),冲床监控项目升级时差点翻车,回滚到4.x才恢复
根因分析: EMQX 5.x是一个大版本重构,配置文件格式从4.x的"emqx.conf + 多个插件配置文件(plugins/emqx_auth_username.conf等)"改成了5.x的"单一emqx.conf(HOCON格式)",所有配置(包括认证/规则/集成/监听器)都在一个文件里,语法也变了(4.x是key = value,5.x是HOCON格式,支持嵌套/包含/变量替换)。冲床监控项目初期用的是EMQX 4.4,看到5.x发布了想升级,直接拉了5.x镜像启动,结果——配置全失效:①认证没了(4.x的emqx_auth_username.conf里的用户名密码,5.x不识别,所有客户端都连不上);②规则引擎没了(4.x的规则存在数据库里,5.x的规则存储格式变了,规则丢失);③数据集成没了(4.x的插件配置,5.x不识别);④监听器端口变了(4.x默认1883/8083/18083,5.x默认一样但配置方式变了)。更坑的是,EMQX 5.x的Dashboard也变了——4.x的Dashboard是独立的插件(emqx-dashboard),5.x的Dashboard内置了,但UI布局和功能位置都变了,老用户需要重新学习。冲床监控项目升级后,30台冲床的设备全断连,数据采集中断,紧急回滚到4.x才恢复,差点影响生产
解决方案: EMQX 4.x升级5.x的正确姿势(6步走):①不要直接升级——先在测试环境验证,用4.x的配置导出(emqx_ctl cluster status / rules list),在5.x里重新配置,确认所有功能正常后再升生产;②配置迁移——5.x提供了配置迁移工具(emqx ctl conf migrate,或官方的迁移指南),可以把4.x的emqx.conf转换成5.x格式,但认证/规则/集成需要手动重新配置(因为存储格式变了);③认证重新配置——5.x的认证在emqx.conf里用authentication块配置,或在Dashboard里可视化配置(访问控制→认证),不要用4.x的插件配置文件;④规则引擎重新创建——5.x的规则引擎SQL语法和4.x基本兼容(都是类SQL),但动作(Action)的配置方式变了(5.x用"数据集成"→"规则"可视化配置),建议在Dashboard里重新创建规则,不要直接复制4.x的规则SQL;⑤数据集成重新配置——5.x的数据集成(Connector/Sink)在Dashboard里可视化配置(数据集成→连接器→创建),支持MySQL/PostgreSQL/TDengine/Kafka等20+,比4.x的插件配置更直观;⑥灰度升级——生产环境用蓝绿部署(新集群5.x和旧集群4.x并行,客户端逐步切换到新集群),不要直接在原集群升级,万一5.x有问题可以随时切回4.x。冲床监控项目最后按这套方法,在测试环境验证了1周,然后灰度切换,顺利升级到5.x,没有影响生产。建议:大版本升级一定要谨慎,先测试后生产,灰度切换,不要直接升级
坑 05 大量客户端连接时Linux端口耗尽——设备远程运维项目的EMQX单机连接数到8万时,新客户端连不上,报"Connection refused"或"Too many open files",查了半天才发现是Linux端口和文件句柄限制
根因分析: EMQX是高连接数的应用——单机可以支持100万+连接,但Linux系统默认的参数是为普通服务器设计的,不支持这么高的连接数。主要有三个限制:①文件句柄数(ulimit -n)——Linux默认每个进程最多打开1024个文件句柄(包括网络连接),EMQX每个连接占用约2-3个文件句柄(socket+缓冲区+进程间通信),1024个句柄只能支持约300-500个连接,超过就报"Too many open files";②本地端口范围(net.ipv4.ip_local_port_range)——Linux默认本地端口范围是32768-60999(约28000个端口),EMQX作为服务端,客户端连接到1883端口,服务端不需要本地端口(服务端用监听端口),但EMQX的规则引擎/数据集成如果要主动连接外部服务(如MySQL/Kafka/HTTP Webhook),每个连接占用一个本地端口,28000个端口上限在大量出站连接时会耗尽;③TCP连接跟踪表(nf_conntrack_max)——Linux内核的连接跟踪表默认大小(如65536或262144),超过后新连接被丢弃,报"nf_conntrack: table full, dropping packet"。设备远程运维项目初期,EMQX单机连接数到8万时,新客户端连不上,查了半天才发现是这三个限制都到顶了——文件句柄1024(早就超了,EMQX启动脚本里改了但没生效)、端口范围28000(出站连接耗尽)、连接跟踪表65536(连接数超了)
解决方案: EMQX高连接数的Linux调优(6个参数):①文件句柄数——/etc/security/limits.conf里设置emqx soft nofile 1048576和emqx hard nofile 1048576(100万),同时检查EMQX启动脚本(systemd service)里的LimitNOFILE=1048576,systemd的限制会覆盖limits.conf,初期就是只改了limits.conf没改systemd,导致不生效;②本地端口范围——/etc/sysctl.conf里设置net.ipv4.ip_local_port_range = 1024 65535(扩大到64512个端口),net.ipv4.tcp_tw_reuse = 1(允许TIME_WAIT状态的端口重用),减少端口耗尽;③连接跟踪表——/etc/sysctl.conf里设置net.netfilter.nf_conntrack_max = 1048576(100万),net.netfilter.nf_conntrack_tcp_timeout_established = 86400(已建立连接超时24小时),如果用了防火墙(iptables/firewalld),连接跟踪表必须调大,不用防火墙可以考虑卸载nf_conntrack模块(但不建议,影响其他功能);④TCP缓冲区——net.core.rmem_max = 16777216(16MB读缓冲)、net.core.wmem_max = 16777216(16MB写缓冲)、net.ipv4.tcp_rmem = 4096 87380 16777216、net.ipv4.tcp_wmem = 4096 65536 16777216,高连接数时大缓冲区减少内存碎片和丢包;⑤EMQX自身参数——emqx.conf里设置node.max_ports = 1048576(Erlang最大端口数)、listeners.tcp.default.max_connections = 1024000(单监听器最大连接数)、zone.external.max_inflight = 32(每个连接最大未确认消息数,防止内存爆炸);⑥监控连接数——用EMQX Dashboard或Prometheus监控连接数(emqx_connections_count),接近阈值时告警,提前扩容(加节点或加服务器)。设备远程运维项目按这套参数调优后,EMQX单机稳定支持20万+连接,CPU<40%,内存<16GB,连续运行半年无异常。建议:EMQX部署时就按高连接数调优,不要等连接数到顶了才调,调优过程中可能断连影响业务

05 性能实测数据(官方基准+项目验证)

100万+
连接数
单机最大连接数(4核8G调优后)
测试环境:官方基准测试,Erlang VM调优
10万+/秒
消息吞吐量
QoS 0消息,单机吞吐量
测试环境:4核8G,payload 256字节
<1ms
消息延迟
平均延迟,P99<5ms
测试环境:局域网,QoS 0,无规则引擎
8-12KB/连接
内存占用
100万连接约8-12GB
测试环境:每个连接约8-12KB(含会话/缓冲区)
60-70%
CPU占用
10万消息/秒时的CPU占用
测试环境:4核服务器,含规则引擎+数据集成
线性扩展
集群扩展
3节点集群支持300万+连接
测试环境:官方基准,水平扩展近线性
📝 测试说明:
  • 官方基准:4核8G服务器,Erlang VM调优,payload 256字节,QoS 0
  • 项目验证:设备远程运维项目,4核8G,20万连接,5万消息/秒,CPU约40%,内存约8GB
  • 连接数:单机100万+连接需要调优Linux内核参数(文件句柄/端口/连接跟踪表)和Erlang VM参数
  • 吞吐量:QoS 0约10万+/秒,QoS 1约5万+/秒,QoS 2约2-3万/秒(QoS越高吞吐量越低)
  • 延迟:局域网QoS 0平均<1ms,P99<5ms;公网延迟取决于网络质量(通常20-100ms)
  • 集群:3节点集群支持300万+连接,水平扩展近线性(增加节点连接数近似线性增加)
  • 结论:EMQX的性能在开源MQTT broker里是顶级的,单机20万连接+5万消息/秒对大多数项目绰绰有余,超过这个规模可以加节点做集群。我们的项目最多用到20万连接,非常稳定,没出过性能问题。

06 vs Mosquitto / RabbitMQ / Kafka 深度对比(10个维度)

对比维度 EMQX Mosquitto RabbitMQ Kafka 胜出
定位 分布式MQTT消息服务器 轻量MQTT broker 多协议消息代理(AMQP为主) 分布式流平台 各有侧重
开发语言 Erlang/OTP(高并发) C语言(极轻量) Erlang/OTP Java/Scala 看场景
最大连接数 100万+(单机) 1万+(单机) 10万+(单机) 不直接支持MQTT EMQX
消息吞吐量 10万+/秒 1万+/秒 5万+/秒 100万+/秒 Kafka
延迟 <1ms(极低) <1ms 1-5ms 10-100ms EMQX/Mosquitto
集群支持 强(分布式,亿级) 无(单节点) 中(镜像/仲裁队列) 强(分布式,分区) EMQX/Kafka
规则引擎 强(SQL+20+集成) 无 弱(插件) 强(Kafka Streams) EMQX
资源占用 中(8-12KB/连接) 极低(<1MB内存) 高(Erlang+Mnesia) 高(JVM+页缓存) Mosquitto
协议支持 MQTT 3/5+WebSocket MQTT 3/5 AMQP+MQTT+STOMP Kafka协议(需代理转MQTT) RabbitMQ
社区规模 极大(全球60%+份额) 大(Eclipse基金会) 大(Pivotal/VMware) 极大(Apache顶级) EMQX/Kafka

📊 对比总结

EMQX胜出的维度(4项):最大连接数、规则引擎(IoT场景)、集群+连接数综合、社区规模(MQTT领域)

Mosquitto胜出的维度(2项):资源占用(极轻量)、延迟(和EMQX并列)

RabbitMQ胜出的维度(2项):协议支持(AMQP为主+MQTT)、复杂路由/事务

Kafka胜出的维度(2项):消息吞吐量、大数据/流处理生态

丁丁的结论:这四个不是替代关系,而是不同场景的不同选择:大规模IoT/工业物联网选EMQX(高连接+MQTT+规则引擎),嵌入式/小规模选Mosquitto(极轻量,<100设备),微服务/复杂消息路由选RabbitMQ(AMQP+事务+死信队列),大数据/日志/流处理选Kafka(极高吞吐+事件溯源)。在工业物联网场景,EMQX几乎是唯一选择——Mosquitto撑不住大规模,RabbitMQ的MQTT是插件性能不行,Kafka不直接支持MQTT。我们的项目全用EMQX,非常稳定,没后悔过。

07 选型建议(什么场景选什么)

✅
选 EMQX
  • 大规模IoT(>1万设备,需要集群/高可用)
  • 工业物联网(设备采集/远程运维/预测维护)
  • 需要规则引擎/数据集成(消息直接写数据库)
  • 云原生部署(Docker/K8s/Operator)
  • 车联网/智能家居/智慧城市(海量设备)
  • 实时消息推送(App/小程序/网页通知)
  • 微服务间异步通信(事件驱动/解耦)
  • 需要中文文档和国内社区支持
🪶
选 Mosquitto
  • 嵌入式/资源受限环境(ARM/<256MB内存)
  • 小规模部署(<100设备,不需要集群)
  • 只需要基础MQTT转发(不需要规则引擎)
  • 边缘网关本地消息中转(配合云端EMQX桥接)
  • 测试/开发环境(快速启动,零配置)
  • 对内存占用极度敏感(Mosquitto<1MB)
  • 不需要管理控制台(命令行配置就行)
  • 项目预算为零且不需要企业功能
📨
选 RabbitMQ / Kafka
  • RabbitMQ:需要AMQP协议(微服务间通信)
  • RabbitMQ:复杂消息路由(主题交换/路由键/headers)
  • RabbitMQ:需要事务性消息/死信队列/延迟队列
  • RabbitMQ:团队已有Erlang/Java运维经验
  • Kafka:大数据/日志/流处理(极高吞吐量)
  • Kafka:事件溯源/CQRS/事件驱动架构
  • Kafka:需要消息长期存储(天/周级别)
  • Kafka:流计算(Kafka Streams/Flink/Spark)

08 部署要点(6步上手指南)

01

安装EMQX

Docker部署(推荐):docker run -d --name emqx -p 1883:1883 -p 8083:8083 -p 8084:8084 -p 18083:18083 -v emqx-data:/opt/emqx/data -v emqx-etc:/opt/emqx/etc --restart=always emqx/emqx:5.7。端口:1883(MQTT TCP)、8083(MQTT WebSocket)、8084(MQTT WSS)、18083(Dashboard)。二进制部署:从官网下载对应平台安装包,解压后./bin/emqx start。APT/YUM安装:添加EMQ的APT/YUM源。K8s部署:用EMQX Operator或Helm Chart。默认Dashboard账号admin/public,首次登录强制改密码

02

基础配置

①修改管理员密码——Dashboard登录后(http://服务器IP:18083),系统设置→用户→修改密码;②配置监听器——emqx.conf里配置listeners.tcp.default.bind = 0.0.0.0:1883(MQTT TCP)、listeners.ws.default.bind = 0.0.0.0:8083(WebSocket),生产环境建议开启TLS;③配置集群——单节点不用配,多节点配置cluster.name = emqx-cluster、cluster.discovery_strategy = static(静态节点列表)或dns(DNS发现);④开启autoheal——cluster.autoheal = true(网络分区恢复后自动愈合,防脑裂);⑤配置日志——log.level = warning(生产环境,减少日志量);⑥备份配置——emqx.conf和data目录定期备份

03

配置认证授权

①内置认证(最简单)——Dashboard→访问控制→认证→创建→选择"内置数据库"→密码哈希方式(sha256/salt)→保存,然后在"用户"里添加用户名密码;②JWT认证(适合App/小程序)——创建认证→选择"JWT"→配置JWT密钥或公钥→配置Token来源→保存;③外部数据库认证——创建认证→选择"MySQL/PostgreSQL/Redis"→配置数据库连接→配置查询SQL→保存;④ACL权限控制——访问控制→授权→创建→配置ACL规则(谁可以发布/订阅哪些主题),默认策略建议设为deny(白名单模式,更安全);⑤测试认证——用MQTT客户端工具(如MQTTX/mosquitto_pub)测试连接,确认认证和ACL都生效

04

配置规则引擎

①理解规则引擎三段式——SQL(SELECT字段+FROM事件+WHERE条件)→ 动作(Action,如写入数据库/发HTTP/republish)→ 否则动作(可选);②创建规则——Dashboard→数据集成→规则→创建→输入SQL→添加动作(如"数据到TDengine",配置连接器和表映射)→保存;③SQL测试——规则创建页面有"SQL测试"功能,输入模拟的clientid/topic/payload,看执行结果;④常用动作——数据到MySQL/PostgreSQL/TDengine/InfluxDB/MongoDB/Redis、发送HTTP请求、republish、console(调试用)、Kafka生产;⑤规则调试——规则列表里可以看规则的执行统计(命中次数/成功次数/失败次数);⑥性能优化——规则引擎的SQL尽量简单,动作尽量批量(数据集成支持批量写入)

05

高可用集群部署

①节点规划——生产环境至少3节点(奇数,防脑裂),节点之间网络延迟<10ms(同机房或同城),不要跨地域部署集群;②节点发现——用static(静态节点列表,在每个节点的emqx.conf里配置cluster.static.seeds)或dns(DNS A记录),生产环境用static最稳定;③负载均衡——客户端连接用负载均衡(Nginx/HAProxy/AWS NLB),把1883端口的TCP连接分发到3个节点,负载均衡器配置健康检查;④会话持久化——EMQX默认会话持久化在内存(节点重启会话丢失),生产环境可以配置会话持久化到外部数据库(如Redis);⑤脑裂防护——开启cluster.autoheal = true,奇数节点部署,网络双网卡冗余,监控集群节点数;⑥滚动升级——集群升级时逐个节点升级,不要同时升级所有节点

06

性能调优与运维

①Linux内核调优——文件句柄(ulimit -n 1048576,systemd的LimitNOFILE也要改)、本地端口范围(net.ipv4.ip_local_port_range = 1024 65535)、连接跟踪表(nf_conntrack_max = 1048576)、TCP缓冲区(rmem_max/wmem_max = 16MB);②Erlang VM调优——emqx.conf里设置node.max_ports = 1048576、node.process_limit = 2097152(进程数上限)、node.fullsweep_after = 1000(GC频率);③EMQX参数——listeners.tcp.default.max_connections = 1024000(单监听器最大连接数)、zone.external.max_inflight = 32(每个连接最大未确认消息数);④监控——用EMQX Dashboard或Prometheus(emqx_exporter)+Grafana做可视化监控,关键指标设告警(接入钉钉/邮件);⑤日志——生产环境日志级别设为warning,日志按天轮转,保留7天;⑥备份——emqx.conf配置文件、data目录定期备份(每天一次,保留7天),升级前必须备份

09 用到EMQX的真实方案

常见问题 FAQ(工程师最常问)

Q:EMQX 是什么?主要用来做什么?

A:EMQ(映云科技)开源的分布式 MQTT 消息服务器,用 Erlang/OTP 开发。主要做工业物联网、车联网、智能家居的海量设备消息接入、转发、规则处理和数据集成,单机支持 100 万以上连接。

Q:EMQX 是免费的吗?开源版和企业版有什么区别?

A:开源,Apache 2.0 协议,可免费商用,核心功能(集群、规则引擎、数据集成)都有。企业版增加 LDAP/SSO 集成、原生数据持久化、专业报表和原厂技术支持。

Q:EMQX 和 Mosquitto 怎么选?

A:大规模、要集群高可用、要规则引擎自动入库,选 EMQX;边缘网关本地、几十到几百设备、资源受限,选 Mosquitto(内存不到 1MB)。

Q:EMQX 单机最多支持多少连接?

A:官方基准为 100 万以上,4核8G 调优后可稳定支持;生产建议单机 10-50 万连接,更多用集群水平扩展。

Q:MQTT QoS 1 消息重复怎么解决?

A:QoS 1 是“至少一次”,网络抖动会重发。消费端做幂等(用唯一 ID 去重),或数据库加唯一索引(INSERT IGNORE);关键业务用 QoS 2。

Q:EMQX 集群怎么搭?怎么防止脑裂?

A:生产用 3/5/7 奇数节点,静态或 DNS 发现,开启 autoheal(网络恢复后自动重启少数派),节点间用双网卡冗余。

Q:EMQX 能直接把消息写入数据库吗?

A:可以,用规则引擎(SQL 选字段)+ 数据集成动作,支持 MySQL、PostgreSQL、TDengine、InfluxDB、Kafka 等 20 多种,不用自己写消费端。

Q:小项目有必要上 EMQX 吗?

A:单机几十点、不要求集群,用 Mosquitto 或直接写库更简单;但预期会扩展、要规则引擎,EMQX 空闲内存也只有几十 MB,一步到位也可。

🎉 6款核心软件深度评测系列收官!

TDengine(存储)+ Node-RED(流程)+ Grafana(展示)+ ThingsGateway(采集)+ Neuron(高性能采集)+ EMQX(消息),覆盖工业数据采集全链路。需要全栈方案设计/部署/优化/咨询,联系丁丁。

联系丁丁咨询 →