
前些天有个做设备联网的朋友发来一份部署文档标题写的是使用emqx部署mtqq服务器点开一看其实是要搭MQTT消息服务。MQTT写成mtqq这个笔误很常见但背后要解决的问题是实打实的几十台设备的数据要稳定送到服务器还要能被多个业务系统订阅消费。我干脆把这次从零部署EMQX的完整过程整理成文把选型、安装、客户端测试、生产环境注意事项全捋一遍。这篇文章适合正在做物联网项目、需要自建消息服务器的开发者也适合第一次接触MQTT、想把发布订阅模型跑通的新手——跟着操作大概半小时就能把一个可用的MQTT服务部署起来。1. 为什么是EMQXMQTT服务器选型背后的逻辑1.1 MQTT到底是什么先对齐概念MQTTMessage Queuing Telemetry Transport消息队列遥测传输是一种基于发布/订阅模式的轻量级消息协议专为网络不稳定、带宽有限、设备资源受限的场景设计。你不需要关心消息怎么路由只需要定义主题Topic发布者往主题里发消息订阅者按主题收消息中间人就是Broker消息代理服务器。这就像小区里的快递柜快递员设备把包裹放进指定格口发布消息收件人业务系统凭取件码订阅主题取件双方不需要知道对方在哪、什么时候有空。快递公司Broker只负责中转和暂存。之所以不用HTTP轮询或者自己维护TCP长连接是因为MQTT把连接保持、断线重连、消息确认、离线补发这些脏活累活都标准化了。一条消息头部最少只要2个字节对4G Cat.1、NB-IoT这类低带宽模块非常友好。1.2 EMQX在众多Broker里赢在哪MQTT Broker不止EMQX一个Mosquitto、Moquette、HiveMQ都是常见选择。我最早用的是Mosquitto轻量、配置简单但做到后面就不够用了连接多了以后管理界面几乎没有客户端断线原因不好排查ACL访问控制要手写配置文件更别提规则引擎和数据桥接。EMQX是国产开源的分布式物联网消息中间件核心用Erlang写的。选它主要看中几点单机连接数上限高单节点可以支撑百万级连接普通项目几十台设备对它来说只是热身。完整的Dashboard从网页上直观看到当前连接数、消息流量、订阅关系还能在线调试。内置认证和ACL用户名密码、JWT、客户端ID黑白名单都可以配不用自己造轮子。规则引擎和WebHook消息到了之后可以直接转发到HTTP服务、数据库或Kafka省掉一层自研消费程序。集群能力开箱即用从单机到多节点配置改动很小这对后面设备量增长很关键。当然如果只是开发环境临时测一下Mosquitto也够用。但既然要往生产上走与其后面迁移不如一开始就选EMQX。1.3 版本怎么选开源版够不够用EMQX分为开源版和企业版。开源版EMQX Open Source基于Apache 2.0协议核心功能完全够日常项目和大多数商业场景用支持Kafka、InfluxDB等数据集成但没有企业级的多数据中心同步、全球消息轨迹等功能。我的建议是先装开源版把业务跑通。等确实需要企业版能力比如跨区域消息同步、统一运维纳管再评估升级到时候数据和配置都可以平滑迁过去不会被厂商锁死。2. 部署前必须搞清楚的MQTT核心概念2.1 主题与通配符消息路由的钥匙MQTT里的主题不是预先创建的而是发布或订阅时动态产生的字符串用斜杠分隔层级。比如设备1上报温度主题可以设计成devices/dev001/telemetry/temperature。订阅端可以用通配符匹配多个主题单层通配符匹配一层比如devices//telemetry/temperature能订阅所有设备上报的温度。#多层通配符匹配剩余所有层级比如devices/#能订阅所有设备的所有消息。这个设计直接影响了整套业务的主题规划。我在实操中的习惯是层级从宽到窄第一层是业务域devices/order/log第二层是设备ID或分组第三层是数据类型telemetry/event/command越靠后越具体。这样后端在订阅时可以用通配符一次收全又方便在规则引擎里按前缀做分流。2.2 QoS级别消息可靠性和性能的权衡MQTT的QoSQuality of Service服务质量分为3级QoS级别语义适用场景QoS 0至多一次发完即焚不确认高频环境传感器丢一帧数据无所谓QoS 1至少一次Broker确认收到可能重复设备状态上报允许偶发重复但要求必达QoS 2恰好一次四次握手保证不重不漏命令下发、支付类消息必须精确一次每个主题的消息都要在可靠和性能之间找平衡。全部用QoS 2没问题但吞吐会明显下降而且QoS 2在弱网下的重传机制会更激进对设备端功耗也不友好。全用QoS 0又会有丢消息的风险。经验做法是上行遥测数据用QoS 0或1下行控制指令用QoS 2。2.3 保留消息和遗嘱消息两个容易被忽略的细节保留消息Retained Message发布消息时把retain标志置1Broker会保存这条消息的最新值。新客户端订阅这个主题时会立即收到这条保留消息而不是傻等下一个发布周期。适合用来下发设备配置、网关状态这类最后一个有效值。遗嘱消息Last Will and TestamentLWT客户端连接时带上遗嘱主题和内容如果客户端异常断开比如断电、网络闪断Broker会替它发布这条遗嘱。很多设备在线状态监控就靠这个实现——设备正常上线时发一条online遗嘱主题在offline业务侧收到offline就知道设备挂了。这两个机制在调试时也很有用。我在测试阶段就靠保留消息订阅验证确认服务是否真正打通省了不少时间。2.4 Clean Session / Clean Start 与会话续传客户端连接时可以指定是否清理会话。若设置为false持久会话Broker会保留该客户端的订阅关系和QoS 1/2离线消息客户端断开后重新连接还能收到离线期间的消息。像设备掉线补报这样的场景就依赖这个机制。这里有一个容易踩的坑持久会话的订阅和离线消息都占Broker内存设备量一大不做清理很快就堆积。EMQX的Dashboard里能看到会话堆积情况生产环境一定要配合心跳超时和会话过期时间一起配置。3. 安装部署实操从下载到Dashboard登录3.1 Windows环境安装EMQX虽然生产服务器大多是Linux但开发机用Windows做验证最方便。EMQX官方提供Windows zip包下载对应版本解压即可用。我这里是5.x版本解压后目录结构是emqx/ ├── bin/ # 启动和管脚本 ├── etc/ # 配置文件主要在 etc/emqx.conf ├── data/ # 运行数据、Mnesia数据库文件 ├── log/ # 日志目录 └── lib/ # 运行库以管理员身份打开PowerShell进入bin目录执行.\emqx start启动完成后检查状态.\emqx status看到Node emqx127.0.0.1 is started之类的输出就说明起来了。然后打开浏览器访问Dashboardhttp://localhost:18083默认账号admin默认密码public登录后第一件事就是改密码。3.2 Linux环境安装apt和二进制包两种方式生产环境建议用LinuxUbuntu/Debian可以直接用官方提供的apt源安装这样升级省心curl -s https://assets.emqx.com/scripts/install-emqx-deb.sh | sudo bash sudo apt-get install emqx sudo emqx startCentOS/RHEL或内网环境建议用二进制zip包和Windows一样解压即用unzip emqx-5.x.x-ubuntu22.04-amd64.zip cd emqx-5.x.x-ubuntu22.04-amd64 ./bin/emqx start ./bin/emqx status这里要注意一个细节生产环境不要用root跑EMQX。官方支持用普通用户身份运行我在部署时单独建了emqx系统用户然后给安装目录授权避免安全问题。3.3 核心端口与配置项EMQX默认涉及的端口如下端口用途1883MQTT over TCP 协议端口8883MQTT over SSL/TLS 端口8083MQTT over WebSocketws8084MQTT over WebSocketwss18083Dashboard管理面板默认监听所有网卡如果只想让内网访问可以修改etc/emqx.conf里的监听配置。比如只允许内网网卡访问MQTT端口把监听地址从0.0.0.0改成具体内网IPlisteners.tcp.default { bind 0.0.0.0:1883 }改完配置后重启./bin/emqx stop ./bin/emqx start有个小建议云服务器上记得在安全组放行1883和18083端口否则外部设备根本连不进来。很多同学本地测试正常一部署到云上就各种超时八成是安全组没放行。3.4 Dashboard里先做的基础设置登录Dashboard后先把三件事办了改管理员密码Dashboard→系统设置→用户管理把默认admin密码改掉。创建业务专用用户不要所有客户端都共用admin。在访问控制→认证里添加用户名密码让设备端用专用账号连接。看监听器和版本号概览页能看到当前版本、节点状态和监听端口确认监听正常。这些虽然简单但太多人忽略后面一旦资源被恶意连接刷爆再回来补就晚了。4. MQTTX客户端连通性测试4.1 用MQTTX做第一轮验证服务起来了不代表业务就通了必须用客户端实际连一下。MQTTX是EMQX官方出品的跨平台MQTT调试客户端支持Windows、macOS、Linux也能在浏览器里直接用Web版。它把订阅、发布、QoS、保留消息这些操作全部可视化了比用命令行mosquitto_pub直观得多。下载安装后新建连接Name随便填比如test-emqxHostmqtt://127.0.0.1远程就填服务器IPPort1883Username/Password在Dashboard里创建的那个业务用户点击Connect右边状态栏变绿就说明TCP连接、MQTT握手、认证全过了。4.2 订阅与发布验证消息链路在MQTTX里添加一个订阅主题填test/topicQoS选1然后点订阅。再开一个客户端或直接用同一个客户端的发布面板往test/topic发一条JSON消息{device_id:dev001,temperature:26.5,humidity:60}正常情况下订阅端立刻能看到这条消息。这时千万别忘了做三件事回到Dashboard的连接管理查看当前客户端连接记录确认连接来自预期IP。在订阅管理里确认订阅关系已经建立。开启Dashboard里的消息追踪如果消息量大追踪功能能帮你确认消息确实经过Broker而不是客户端之间直连传的。4.3 WebSocket连接也测一遍很多场景下设备端或前端页面没法走TCP 1883比如浏览器里的可视化大屏就要走WebSocket。MQTTX也支持这个新建连接时把协议换成ws://端口填8083ws://127.0.0.1:8083/mqtt注意URL末尾的/mqtt路径这是EMQX WebSocket的默认路径漏掉就连不上。测通了WebSocket后面的前端订阅就会顺畅很多。5. 从能用到好用生产环境要补的几块拼图5.1 认证和权限控制裸奔的MQTT服务就是一块肥肉谁都能连接、谁都能订阅全量数据。EMQX的认证优先级顺序是客户端ID认证黑白名单→ 用户名密码认证 → JWT → 匿名认证。生产环境至少打开用户名密码认证再开启ACL限制订阅范围。开启方式Dashboard→访问控制→认证选Password-Based数据源用内置数据库把前面创建的业务用户挂上去。ACL规则简单理解就是谁允许发布/订阅哪个主题比如只允许dev001这台设备发布到devices/dev001/#其他主题一律禁止。如果没有特殊设计匿名认证务必关掉。物联网设备被入侵的路径里消息中间件裸奔排得很靠前。5.2 规则引擎:把消息转发到业务系统设备上报的数据不能永远堆在Broker里要落到业务库或消息队列。EMQX的规则引擎可以在消息到达时直接转发省掉自己写一个消费者程序。比如把每条消息POST到自己的HTTP接口在Dashboard里规则页面新建规则SQL先做一次筛选SELECT clientid AS client_id, payload.temperature AS temp, payload.humidity AS hum, topic FROM devices//telemetry/然后添加一个动作选发送数据到Web服务填上你后端接口的地址字段映射选JSON。这样每一条匹配的消息都会实时打到你的HTTP接口里业务系统只管接收就行。这条链路我实测稳定跑过很长时间比自己在后端写一个MQTT客户端去消费更省心少了客户端容易掉线重连的那一堆破事而且重启Consumer不用考虑消息补偿因为规则引擎面向的是实时流。5.3 集群部署要点如果设备量上万或者对高可用有要求就要考虑集群了。EMQX集群配置比很多中间件简单核心是让各节点发现彼此。最省事的方式是让节点通过静态节点列表互相注册修改每台机器的etc/emqx.confcluster { name emqx_cluster discovery_strategy static static { seeds [10.0.0.1:4370, 10.0.0.2:4370] } }然后一台一台启动集群会自动协商。需要注意两点一是集群节点之间4370端口的TCP连通性要保证二是一旦集群成功不要随意在设备多的时候动态调换节点列表节点发现异常容易引起集群抖动。集群并不能解决在所有节点都能看到同一份离线消息这类需求那是持久化层的活别把集群当成消息持久化的替代品。5.4 监控与告警EMQX Dashboard自带基础的负载、连接数、消息速率曲线但我建议把http_api的指标接入Prometheus配合Grafana做长期监控。这样当连接数突增、消息堆积超过阈值时能第一时间收到告警而不是等客户反馈设备怎么不上线了才发现Broker已经挂了。6. 实测中踩过的坑6.1 客户端连不上先分三层排查遇到连接失败我一般按三层排查网络层从客户端机器上用telnet 服务器IP 1883测端口通不通。不通就先查防火墙、安全组、云平台网络策略。协议层确认客户端用的是MQTT协议而不是MQTT over WebSocket很多客户端默认走WebSocket结果端口本来是1883就连不上。端口写错是最常见的坑。认证层确认用户名密码正确Dashboard认证规则没写错客户端ID没有和别的设备撞车。这三层走完99%的连接问题都能定位。6.2 端口冲突1883被占用有次部署到一台老服务器emqx start显示成功但客户端怎么都连不上1883。查日志才发现端口被另一个服务占了。排查命令ss -lntp | grep 1883解决方式是改端口。EMQX的配置里监听器可以随意改名绑定新端口但注意如果改了非默认端口客户端和防火墙规则都要跟着改工作量不小不如直接换台干净的机器。6.3 客户端ID撞车导致互相踢下线MQTT协议中同一个客户端ID同时只允许一个连接存活。如果设备端把客户端ID写死成相同的值后连接的设备会把先连接的顶掉线两个设备就会反复重连像一对互相挤位子的冤家。排查方法Dashboard的连接管理里看连接是否有频繁断开又重连的记录确认客户端ID是否重复。设备端一定要保证客户端ID唯一通常用设备序列号或MAC地址来拼。6.4 保留消息把过期数据发给新订阅者保留消息用久了也会翻车。某个主题发布端下线后它最后一条保留消息还在Broker里任何新订阅这个主题的客户端都会立刻收到这条过期数据。业务上如果把这个当成最新状态还好如果当成新事件处理就会出问题。我的处理方式是在业务逻辑里给保留消息加时间戳消费端判断如果消息时间超过一定阈值就丢弃或者在下线场景里主动发布一条空消息到保留主题把旧值清掉。6.5 日志定位不要只看错误级别EMQX的日志文件在log/目录下出错时第一反应是去查error级别日志但实际上很多消息丢失、订阅异常的问题关键线索都藏在debug级别的日志里。遇到诡异问题把日志级别调到debug复现一次看客户端上线、订阅、发布各个阶段的具体交互过程比对着配置文件猜要快得多。6.6 心跳超时设置不当导致设备被频繁断开MQTT协议里有Keep Alive心跳机制客户端会在空闲时发送PINGREQ包保活。如果心跳时间设置太长Broker无法及时发现设备掉线设置太短弱网下设备没有及时发心跳就会被Broker判定离线触发遗嘱消息误报。一般经验心跳间隔设置为设备正常上报周期的1.5到2倍最小不要低于10秒。设备端和Broker端的心跳参数要一致否则会出现设备端觉得自己还活着Broker已经把它清了的抓狂场景。7. 写在最后的一些运维建议整个部署链路走下来我有几个很深的感受第一MQTT的消息语义和HTTP完全不同。它不是一个请求-响应协议而是异步的、事件驱动的。刚从Web开发转过来的同学最容易犯的错就是用HTTP的思路去等待一条消息的返回结果然后被各种超时整崩溃。心态上要先接受发出去不代表对方收到收到不代表处理完再谈稳定性。第二EMQX虽然部署简单但真正麻烦的是业务侧的主题设计、QoS规划、认证策略。这些事在设备量小的时候看不出来一旦上了规模改动成本会指数级上升。所以我强烈建议哪怕现在只有十台设备也按生产标准来设计主题和权限。第三消息这块的排查思路核心是分段验证Broker有没有收到消息追踪、有没有转发规则引擎日志、下游有没有消费业务日志。每一段都确认了问题就自然浮出来。不要一上来就怀疑中间件有问题多数时候是自己的配置或代码问题。如果你也是第一次部署建议先在本机把EMQX和MQTTX这套组合跑通再往服务器上搬。整个过程并不复杂难的是把每一个概念吃透、把每一个配置项背后的动机搞清楚。这套基础打好了后面做设备管理、数据上报、远程控制都会顺很多。