消息接入方案分析与决策
在 YunStack-IoT 项目中,后端服务如何从 EMQX 获取设备数据是一个关键架构决策。主要有两种主流方式:Webhook 和 MQTT 客户端订阅。
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 为什么当前不引入?
- 避免过度设计 (Over-Engineering):引入 MQ 会显著增加架构复杂度和运维成本(需要维护 MQ 集群的高可用、持久化等)。对于初期及中期的设备规模(万级以下),这是不必要的负担。
- 性能冗余充足:
- Node.js 优势:NestJS (Node.js) 处理 I/O 密集型任务极其高效。单实例处理数千 TPS 的写入通常无压力。
- EMQX 能力:EMQX 本身具备极高的吞吐能力,且支持共享订阅 ($share)。
- 替代方案:共享订阅 (Shared Subscription)
- 当单机 NestJS 无法支撑时,我们只需横向扩展 NestJS 实例,并使用 MQTT 共享订阅模式(如
$share/group1/sys/+/+/thing/#)。 - EMQX 会自动在多个 NestJS 实例间进行消息的负载均衡,实际上起到了类似 MQ 的“分发”作用。
- 当单机 NestJS 无法支撑时,我们只需横向扩展 NestJS 实例,并使用 MQTT 共享订阅模式(如
3.2 何时考虑引入 MQ?
我们将“引入 MQ”作为未来架构演进的里程碑。触发条件包括:
- 业务逻辑极重:数据处理涉及复杂的 CPU 密集型计算,阻塞 Event Loop。
- 多服务解耦:同一份数据需要分发给多个独立的异构系统(如实时告警、大数据分析、第三方推送)。
- 削峰填谷需求:面对百万级设备同时上报的极端并发场景。
4. YunStack-IoT 的决策总结
我们采用 混合模式 (Hybrid Pattern):
高频业务数据 (Telemetry/Command):
- 方式:后端服务内部集成 MQTT Client。
- 实现:NestJS 启动时连接 EMQX,订阅
sys/+/+/thing/event/property/post等业务 Topic。 - 优点:极低延迟,极低带宽开销,能够承载未来扩展的高频传感器数据。
低频系统事件 (Online/Offline):
- 方式:EMQX Webhook。
- 实现:在 EMQX 配置 Webhook,当发生
client.connected和client.disconnected事件时,回调后端 HTTP 接口/api/webhook/emqx。 - 优点:状态同步可靠,即使后端短暂重启,也能在恢复后收到补发的上下线通知。
