Skip to content

消息接入方案分析与决策

在 YunStack-IoT 项目中,后端服务如何从 EMQX 获取设备数据是一个关键架构决策。主要有两种主流方式:WebhookMQTT 客户端订阅

1. 方案对比

特性方案 A: Webhook (HTTP 推送)方案 B: 后端作为 MQTT Client (TCP 长连接)
工作原理EMQX 收到消息后,发起 HTTP POST 请求调用后端 API。后端服务启动一个 MQTT 客户端,通过 TCP 长连接订阅通配符 Topic (如 sys/+/+/thing/#)。
连接开销。每条消息都是一次 HTTP 请求(握手、传输、断开)。虽有连接池,但相比长连接仍重。极低。建立一条 TCP 长连接后,所有消息通过该管道传输。
吞吐量较低。受限于 HTTP 协议开销和 Web Server 并发处理能力。高频上报易造成阻塞。极高。Node.js 处理 TCP 流极其高效,适合高频小包。
可靠性高 (带重试)。EMQX 可配置重试队列,后端宕机重启后可补发。中 (依赖 QoS)。需配合持久化会话 (Clean Session=false) 和 QoS 1 才能在重连后补齐离线消息。
实时性毫秒级,但受网络抖动影响略大。微秒/毫秒级,即时性最好。
适用场景低频、关键事件(如设备上下线、报警)。高频、流式数据(如传感器实时采样、日志流)。

2. 详细分析:为什么采用混合模式?

2.1 为什么传感器数据不推荐使用 Webhook?

  • 高并发压力:假设系统有 1000 个设备每秒上报一次数据,使用 Webhook 意味着后端服务每秒需处理 1000 个 HTTP 请求。这会产生巨大的协议开销(HTTP Header 往往比 MQTT Payload 还大),并对后端 HTTP Server 造成极大的并发压力。
  • 带宽利用率低:相比之下,MQTT 是轻量级协议。后端作为 MQTT 客户端订阅时,每秒只需处理 1000 个极小的 TCP 包,几乎没有额外协议头开销,且无需反复握手。

2.2 为什么设备上下线感知推荐使用 Webhook?

  • 低频但关键:设备上下线属于低频事件,但对业务逻辑(如前端展示在线状态)至关重要。
  • 可靠性保障
    • 如果后端服务重启,作为 MQTT 客户端的 TCP 连接会断开,期间产生的“设备下线”消息极易丢失(除非配置复杂的 QoS 1 + 持久化会话)。
    • 而 Webhook 机制通常带有缓冲和重试功能。如果后端重启期间 EMQX 推送失败,EMQX 会在后端恢复后自动重试推送,确保不会漏掉“设备下线”等关键状态变化。

3. 补充讨论:是否需要引入消息队列 (MQ)?

关于“是否需要在 EMQX 和 NestJS 之间引入 Kafka/RabbitMQ”,我们目前的决策是:当前阶段不需要

3.1 为什么当前不引入?

  1. 避免过度设计 (Over-Engineering):引入 MQ 会显著增加架构复杂度和运维成本(需要维护 MQ 集群的高可用、持久化等)。对于初期及中期的设备规模(万级以下),这是不必要的负担。
  2. 性能冗余充足
    • Node.js 优势:NestJS (Node.js) 处理 I/O 密集型任务极其高效。单实例处理数千 TPS 的写入通常无压力。
    • EMQX 能力:EMQX 本身具备极高的吞吐能力,且支持共享订阅 ($share)
  3. 替代方案:共享订阅 (Shared Subscription)
    • 当单机 NestJS 无法支撑时,我们只需横向扩展 NestJS 实例,并使用 MQTT 共享订阅模式(如 $share/group1/sys/+/+/thing/#)。
    • EMQX 会自动在多个 NestJS 实例间进行消息的负载均衡,实际上起到了类似 MQ 的“分发”作用。

3.2 何时考虑引入 MQ?

我们将“引入 MQ”作为未来架构演进的里程碑。触发条件包括:

  • 业务逻辑极重:数据处理涉及复杂的 CPU 密集型计算,阻塞 Event Loop。
  • 多服务解耦:同一份数据需要分发给多个独立的异构系统(如实时告警、大数据分析、第三方推送)。
  • 削峰填谷需求:面对百万级设备同时上报的极端并发场景。

4. YunStack-IoT 的决策总结

我们采用 混合模式 (Hybrid Pattern)

  1. 高频业务数据 (Telemetry/Command)

    • 方式:后端服务内部集成 MQTT Client。
    • 实现:NestJS 启动时连接 EMQX,订阅 sys/+/+/thing/event/property/post 等业务 Topic。
    • 优点:极低延迟,极低带宽开销,能够承载未来扩展的高频传感器数据。
  2. 低频系统事件 (Online/Offline)

    • 方式:EMQX Webhook。
    • 实现:在 EMQX 配置 Webhook,当发生 client.connectedclient.disconnected 事件时,回调后端 HTTP 接口 /api/webhook/emqx
    • 优点:状态同步可靠,即使后端短暂重启,也能在恢复后收到补发的上下线通知。