MQTT 桥接(Bridging)介绍
MQTT 桥接(Bridge)是指一台 MQTT broker 作为客户端连接到另一台 broker,并在两者之间转发消息的机制。常见于「本地(边缘端)→ 云端」的物联网架构中:本地部署一台轻量 broker,负责就近接入现场设备;云端部署一台 broker,负责汇聚所有本地节点的数据。
桥接模式的好处
- 弱网可靠传输:本地 broker 与云端断开时,消息先在本地缓存(持久化会话 + QoS),网络恢复后自动续传,做到「断网不丢数据」。
- 降低云端连接数:现场大量设备只需连本地 broker,云端只需面对「每个本地节点一条桥接连接」,而不是成百上千的设备直连,大幅降低云端压力与运维复杂度。
- 本地自治:即使与云端断连,本地设备之间的消息仍可在本地 broker 内正常路由,现场业务不受影响。
- 安全隔离:本地 broker 作为唯一出网出口,可在桥接层统一做认证、加密(TLS)和 ACL 控制,避免设备直接暴露在公网。
- 统一接入标准:本地与云端统一使用 MQTT 协议,Topic 规划一致,便于横向扩展多个本地节点。
应用场景
- 工业现场数据采集:工厂、站点等本地设备采集数据,经本地 broker 桥接到云平台做集中监控与数据分析。
- 边缘计算协同:本地完成实时处理,云端完成大数据分析、历史存储与全局调度。
- 远程设备管理:云端通过桥接反向下发指令到本地,实现远程配置、控制与 OTA 升级。
- 多节点汇聚:大量分布式节点(如分布式站点、分散设备群)通过桥接统一汇入一个云端中心。
几种MQTT broker比较,比较
emqx
- 社区版只能单结点部署
- 社区版有消息配额
针对本地与云通信架构(本地(边缘端)Mosquitto 桥接 → 云端 VerneMQ),以下是三个问题的具体实现方法,合并到一个带配置文件启动的完整方案中。
VerneMQ
- 配制比较复杂
- Star数较少,可能有较多BUG
Mosquitto
Mosquitto 用 C 语言编写,单节点性能非常强悍。根据社区实际部署案例和压测数据:
- 并发连接数:单台云服务器(4核8G)经系统调优(主要是
ulimit -n和 TCP 参数)后,Mosquitto 可以稳定支撑 5万~10万 的持久 TCP 长连接。1万个本地(边缘端)节点(每个节点一条桥接连接)完全在其能力范围内。 - 消息吞吐量:单节点每秒可处理 数十万到百万条 小消息的路由,对于遥测类数据(每秒一条甚至更低频率)绰绰有余。
- 资源占用:维持 1 万连接时,内存占用通常在 数百 MB 到 1GB 左右,CPU 消耗主要取决于消息速率,一般不会成为瓶颈。
结论:单从“接得住”这个角度看,1万个本地(边缘端)节点用一个 Mosquitto 单节点是完全可行的。
Mosquitto HA: 双机冗余部署
Keepalived + 主备自动切换
原理:两台 Mosquitto 服务器,一主一备。通过 keepalived 提供一个虚拟 IP(VIP),本地(边缘端)桥接都指向这个 VIP。主节点宕机时,VIP 自动飘到备节点,并启动备节点的 Mosquitto 服务。本地(边缘端)桥接断开后自动重连,恢复数据上报。
优点:
- 部署简单,不需共享存储。
- 自动切换,中断时间通常 < 30 秒。
- 本地(边缘端)上行数据零丢失(本地缓存续传)。
缺点:
- 主备切换期间,下行指令会短暂中断,原暂存的下行消息会丢失(可通过业务重试机制弥补)。
- 需要编写简单的检测和拉起脚本。
实现步骤(假设两台机器 192.168.1.10 和 192.168.1.20,VIP 为 192.168.1.100):
- 两台机器都安装 Mosquitto 并保持相同配置(特别是
password_file、acl_file、桥接相关的配置没有,这是云端)。两台的/data/mosquitto-cloud目录结构一致,密码文件手工同步。 - 备机默认不启动 Mosquitto(或启动但监听不同端口),通过
keepalived的notify_master脚本在升主时启动 Mosquitto,在降为备时停止。 - keepalived 配置示例(主节点):
备机类似,vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1234 } virtual_ipaddress { 192.168.1.100 } notify_master "/etc/keepalived/become_master.sh" notify_backup "/etc/keepalived/become_backup.sh" }state BACKUP,priority 90。 become_master.sh脚本内容:#!/bin/bash systemctl start mosquittobecome_backup.sh:#!/bin/bash systemctl stop mosquitto- 本地(边缘端)桥接配置中
address一律填写192.168.1.100。
这样,主节点故障后,VIP 漂移,备机启动 Mosquitto,本地(边缘端)桥接会在 restart_timeout 时间内重连,继续上传数据。这是目前社区最成熟的 Mosquitto HA 做法。
云端Mosquitto部署
在云端部署 Mosquitto 作为本地(边缘端)节点接入点,核心任务是开启认证、持久化会话、并准备好接收来自本地(边缘端)Mosquitto 桥接的 MQTT 连接。以下是完整的云端部署过程(使用 Docker)。
1. 目录准备
mkdir -p /data/mosquitto-cloud/config /data/mosquitto-cloud/data /data/mosquitto-cloud/log
# 容器内 mosquitto 用户 uid=1883
chown -R 1883:1883 /data/mosquitto-cloud
2. 编写云端 Mosquitto 配置文件
创建 /data/mosquitto-cloud/config/mosquitto.conf:
# 监听 1883 端口
listener 1883 0.0.0.0
# 禁止匿名,使用密码文件
allow_anonymous false
password_file /mosquitto/config/passwd
# 持久化(断网续传需要)
persistence true
persistence_location /mosquitto/data
persistent_client_expiration 30d
# 日志
log_dest file /mosquitto/log/mosquitto.log
log_type error
log_type warning
log_type notice
log_type information
说明:
- 同时监听
1883(明文,内网桥接或测试)和8883(TLS,公网桥接)。 - 必须使用
allow_anonymous false并指定password_file,所有客户端(包括本地(边缘端)桥接)必须提供用户名密码。 - 证书文件(
ca.crt,server.crt,server.key)请提前准备好,若暂时没有 TLS 证书,可先只开放 1883,生产环境务必启用 8883。
3. 生成密码文件
docker run -d --name mosquitto-temp -v /data/mosquitto-cloud/config:/config eclipse-mosquitto
docker exec -it mosquitto-temp mosquitto_passwd -c /config/passwd ocean-dev
# 完成后删除临时容器
docker rm -f mosquitto-temp
4. 权限
【可选】证书文件放入 /data/mosquitto-cloud/config/certs/ 目录下,例如:
chown -R 1883:1883 /data/mosquitto-cloud/data
chown 1883:1883 /data/mosquitto-cloud/config/passwd
5. 启动容器
前台模式
docker run --rm -it \
-v /data/mosquitto-cloud/config/mosquitto.conf:/mosquitto/config/mosquitto.conf \
-v /data/mosquitto-cloud/config/passwd:/mosquitto/config/passwd \
-v /data/mosquitto-cloud/data:/mosquitto/data \
-v /data/mosquitto-cloud/log:/mosquitto/log \
-p 1883:1883 \
eclipse-mosquitto
后台模式
docker run -d \
--name mosquitto-cloud \
--restart unless-stopped \
-v /data/mosquitto-cloud/config/mosquitto.conf:/mosquitto/config/mosquitto.conf \
-v /data/mosquitto-cloud/config/passwd:/mosquitto/config/passwd \
-v /data/mosquitto-cloud/data:/mosquitto/data \
-v /data/mosquitto-cloud/log:/mosquitto/log \
-p 1883:1883 \
eclipse-mosquitto
6. 验证部署
查看日志确认启动正常:
docker logs mosquitto-cloud
应无严重错误,并看到监听端口信息。
本地测试认证是否生效:
# 无认证会被拒绝
mosquitto_sub -h 192.168.1.100 -t 'test/topic' -v
# 预期报错:Connection Refused: not authorised
# 带正确认证应成功
mosquitto_sub -h 192.168.1.100 -t 'test/topic' -u ocean-dev -P Initpass@word1 -v
# 消息订阅发送测试
mosquitto_sub -h 10.4.96.16 -t 'test/topic' -u ocean-dev -P Initpass@word1 -v
mosquitto_pub -h 10.4.96.16 -t 'test/topic' -m "hello world from EMVQ" -u ocean-dev -P Initpass@word1
本地(边缘端)Mosquitto 部署
在本地(边缘端)部署一个 Mosquitto,通过桥接连接到云端 Mosquitto,是保障弱网下数据不丢失。 以下操作在本地的 Linux 主机或虚拟机上完成(假设使用 Docker)。
1. 目录准备与权限设置
mkdir -p /data/mosquitto-local/config /data/mosquitto-local/data /data/mosquitto-local/log
# 容器内 mosquitto 用户 uid=1883
chown -R 1883:1883 /data/mosquitto-local
2. 编写本地 Mosquitto 配置文件
创建 /data/mosquitto-local/config/mosquitto.conf:
# 网络隔离; 供本地调用;本地局域网 IP 和云端局域网连接
# listener 1883 127.0.0.1
# listener 1883 192.168.1.100
listener 1883 0.0.0.0
allow_anonymous true
# 持久化
persistence true
persistence_location /mosquitto/data
max_queued_messages 100000
persistent_client_expiration 30d
# 日志
log_dest file /mosquitto/log/mosquitto.log
log_type error
log_type warning
log_type notice
log_type information
# ========== 桥接到云端 ==========
connection cloud-bridge
address 10.4.96.16:1883
# topic <主题> <方向> <QoS> <本地前缀> <远程前缀>; 方向 both:双向同步; QoS 2:桥接传输使用 QoS 2(精确一次)
topic # both 2 "" ""
cleansession false
notifications true
start_type automatic
restart_timeout 10 30
keepalive_interval 60
bridge_protocol_version mqttv311
remote_username ocean-dev
remote_password Initpass@word1
注意:
address改为你云端 Mosquitto 的实际 IP。remote_username和remote_password必须与云端passwd文件中配置的用户名密码一致。- 如果云端只开启了 TLS(8883),则需要将
address改为192.168.1.100:8883并添加bridge_cafile等 TLS 参数。
3. 启动本地 Mosquitto 容器
# debug
docker run -it \
--name mosquitto-local \
--restart unless-stopped \
-p 1883:1883 \
-v /data/mosquitto-local/config/mosquitto.conf:/mosquitto/config/mosquitto.conf \
-v /data/mosquitto-local/data:/mosquitto/data \
-v /data/mosquitto-local/log:/mosquitto/log \
eclipse-mosquitto
# deploy
docker run -d \
--name mosquitto-local \
--restart unless-stopped \
-p 1883:1883 \
-v /data/mosquitto-local/config/mosquitto.conf:/mosquitto/config/mosquitto.conf \
-v /data/mosquitto-local/data:/mosquitto/data \
-v /data/mosquitto-local/log:/mosquitto/log \
eclipse-mosquitto
4. 验证桥接是否成功
查看容器日志:
docker logs mosquitto-local | grep -i bridge
正常时会看到类似:
Notice: Connecting bridge cloud-bridge (192.168.1.100:1883)
Notice: Bridge cloud-bridge is connected
功能测试:
- 在本地发布一条消息:
docker exec mosquitto-local mosquitto_pub -t local/test -m "hello from local" -q 2 - 在云端订阅验证是否能收到:
# 在云端服务器上 docker exec mosquitto-cloud mosquitto_sub -t 'local/#' -u bridge_user -P YourPassword -v - 反向测试:云端发布,本地订阅,确认双向通信正常。
断网续传测试:
- 断开本地网络(或临时停止云端 Mosquitto)。
- 本地继续发布几条消息到本地 Broker。
- 恢复网络后,检查云端是否收到所有离线消息,确保没有丢失。
5. 可选:本地也启用密码认证
如果希望本地也要求客户端认证,可添加:
allow_anonymous false
password_file /mosquitto/config/passwd
并使用之前的方法生成密码文件并挂载。不过,桥接使用的 remote_username 和 remote_password 是云端认证,本地认证与桥接无关。
部署完成后,mosquitto-local 即成为本地消息枢纽,同时自动与云端保持同步,实现弱网下的可靠通信。
