本地与云 MQTT通信:消息格式定义与配置


发布者 ourjs  发布时间 1787276042930
关键字 消息中间件 

在本地与云 MQTT 通信分层架构中,这几个 Client ID 分别作用于不同的 Broker 连接,彼此隔离但协同工作。下面梳理它们的角色与关系。


1. 三个 Client ID 的归属

Client ID 所属连接 注册的 Broker 作用
mqtt-app 本地(边缘端)应用程序 → 本地 Mosquitto 本地(边缘端)Broker 本地 Broker 为这个客户端维护持久会话、离线消息队列
mqtt-local 本地(边缘端)Mosquitto 桥接 → 云端 Mosquitto 云端 Broker 云端 Broker 为这个本地节点的桥接维护持久会话、离线指令队列
mqtt-cloud 云端某个客户端(如监控程序) → 云端 Mosquitto 云端 Broker 云端 Broker 为云端应用维护会话(通常用于订阅上行数据或下发指令)

2. 它们如何协同工作

上行数据(本地 → 云)

  1. 本地(边缘端)应用程序以 mqtt-app 身份连接本地 Broker,发布数据到 local/node-001/data
  2. 本地 Broker 接收该消息。由于配置了桥接且同步主题 # both桥接作为本地 Broker 的内部消费者会获得该消息。
  3. 桥接以 mqtt-local 身份连接云端 Broker,将这条消息发布到云端 Broker 的同一主题。
  4. 云端订阅了该主题的客户端(如 mqtt-cloud)就会收到消息。

关键点

  • 消息在云端 Broker 上的发布者(Publisher Client ID)是 mqtt-local,而不是原始的 mqtt-app。这实现了本地(边缘端)内部客户端的身份屏蔽。
  • 如果需要在云端区分具体节点或设备,必须在消息主题或载荷中编码标识(如 local/node-001/engine/data),而不能依赖 Client ID。

下行指令(云 → 本地)

  1. 云端应用(如 mqtt-cloud)向 local/node-001/cmd 发布指令。
  2. 云端 Broker 将该指令分发给所有订阅该主题的客户端,包括本地(边缘端)桥接 mqtt-local
  3. 本地(边缘端)桥接收到指令后,注入本地 Broker,本地 Broker 再分发给订阅了该主题的本地客户端(如 mqtt-app)。
  4. 如果本地(边缘端)应用程序此时离线(mqtt-app 已断连但会话保留),本地 Broker 会暂存该指令,待其重连后补发。

离线断网续传

  • 本地与云链路断开:桥接 mqtt-local 与云端 Broker 失去连接。云端 Broker 根据 mqtt-local 的持久会话,将期间下发的 QoS≥1 指令暂存起来。
  • 网络恢复:桥接以 mqtt-local 身份重连云端,云端立即将所有暂存指令推送给桥接,桥接再转入本地 Broker,最终送达 mqtt-app

3. 常见误解澄清

  • Client ID 必须在整个链路中唯一吗?
    不,只需在同一个 Broker 内唯一。本地(边缘端)Broker 上的 mqtt-app 与云端 Broker 上的 mqtt-local 不在同一 Broker,可以重名,但为避免混淆建议用不同名称。

  • mqtt-cloud 是必须的吗?
    不是,它只是示例表示云端任何消费或发送消息的客户端。云端可以有许多不同 Client ID 的应用,各自订阅不同主题。

  • 桥接为何不用 mqtt-app 作为 Client ID?
    桥接是一个独立的 MQTT 客户端,它必须使用自己的 ID 连接云端。如果也使用 mqtt-app,云端 Broker 会认为与本地某个应用重名,导致冲突。


4. 最佳实践建议

  • 本地设备 Client ID:使用 {节点标识}-{设备/功能},如 node001-engine
  • 桥接 Client ID:在本地(边缘端)mosquitto.conf 中显式设置 clientid node001-bridge,确保集群内唯一。
  • 云端客户端:按用途命名,如 cloud-monitorcloud-db-writer
  • 节点标识:嵌入在消息主题中,如 local/node001/data,这样云端仅凭主题就能区分来源,无需依赖 Client ID。

通过这种分层与命名策略,每个 Client ID 各司其职,既保证了离线消息的精准补发,又实现了本地与云身份的清晰解耦。

好的,我们按照你的要求在主题中显式添加上下行标志,使协议更规范、订阅更可控,同时保持消息载荷的精简。


一、主题设计(含上下行方向)

主题结构:

{scope}/{entity}/{direction}/{msg_type}
层级 说明 取值示例
{scope} 作用域 local(点对点)、group(广播)
{entity} 实体标识 节点ID(如 n001),若为广播可省略
{direction} 方向标志 up(上行,本地→云)、down(下行,云→本地)
{msg_type} 消息类型 telemetryalertheartbeatcommandcmd_ack

主题示例

上行(本地→云)

  • local/n001/up/telemetry —— 遥测数据
  • local/n001/up/alert —— 告警
  • local/n001/up/heartbeat —— 心跳
  • local/n001/up/cmd_ack —— 指令确认

下行(云→本地)

  • local/n001/down/command —— 对单节点指令
  • group/broadcast —— 对全集群的广播

订阅方式

  • 云端接收所有本地节点上行数据:local/+/up/#
  • 云端监听所有指令确认:local/+/up/cmd_ack
  • 本地(边缘端)接收自己的指令:local/n001/down/#
  • 所有本地节点接收广播:group/broadcast

二、消息载荷(Payload)

载荷保持极简:固定包含 ts 和 data 字段,不同消息类型在 data 中携带具体业务数据。

1. 遥测数据(上行)

主题:local/n001/up/telemetry

{
  "ts": "2026-07-21T12:00:05Z",
  "data": {
    "lat": 31.2304,
    "lon": 121.4737,
    "sog": 12.5,
    "cog": 235.0
  }
}

2. 告警(上行)

主题:local/n001/up/alert

{
  "ts": "2026-07-21T12:05:00Z",
  "data": {
    "level": "critical",
    "code": "FIRE_ENGINE_ROOM",
    "desc": "机舱火警触发"
  }
}

3. 心跳(上行)

主题:local/n001/up/heartbeat

{
  "ts": "2026-07-21T12:10:00Z",
  "data": {
    "online": true,
    "queue_depth": 12
  }
}

4. 控制指令(下行)

主题:local/n001/down/command

{
  "ts": "2026-07-21T13:00:00Z",
  "data": {
    "cmd_id": "cmd-1234",
    "action": "update_route",
    "params": {
      "waypoints": [
        {"lat": 31.5, "lon": 122.0, "speed": 10}
      ]
    }
  }
}

5. 指令确认(上行)

主题:local/n001/up/cmd_ack

{
  "ts": "2026-07-21T13:01:05Z",
  "data": {
    "cmd_id": "cmd-1234",
    "status": "accepted",
    "reason": "已开始执行航线更新"
  }
}

6. 集群广播(下行)

主题:group/broadcast

{
  "ts": "2026-07-21T12:30:00Z",
  "data": {
    "type": "weather_warning",
    "title": "台风蓝色预警",
    "content": "预计未来24小时内东海海域风力将达8级,请就近避风。",
    "valid_until": "2026-07-22T12:00:00Z"
  }
}

三、设计要点说明

设计选择 理由
主题中显式up/down 订阅端可立即区分消息流向,无需解析载荷;便于 ACL 权限控制(如本地(边缘端)只允许发布 up 主题,只允许订阅 down 主题);未来监控/统计可直接按方向过滤。
统一 ts 时间戳 所有消息带本地(边缘端)产生时间(UTC),简单可靠,无需额外字段。
指令使用 cmd_id 唯一标识一条指令,去重和状态追踪都依赖它,精简但够用。
载荷无通用外层包裹 避免过度嵌套,APP 层直接解析 data 获取业务内容。

四、对现有本地与云架构的适配

  • 本地(边缘端)桥接:同步主题可设为 local/n001/#(双向)或更精确的 local/n001/up/#(上行)和 local/n001/down/#(下行),确保方向明确。
  • 云端 Broker:可以配置 ACL,禁止本地(边缘端)客户端发布 down 主题,防止伪造指令。
  • APP 订阅:本地(边缘端)APP 只需订阅 local/{my_node_id}/down/# 和 group/down/broadcast,就能收到所有指令和广播,同时自己发布到 local/{my_node_id}/up/...

这样就实现了一套方向明确、结构统一、轻量实用的本地与云消息协议。









  开源的 OurJS
OurJS开源博客已经迁移到 OnceOA 平台。

  关注我们
扫一扫即可关注我们:
OnceJS

OnceOA