# IoT 设备接入平台 架构模板 > **代表产品 / 原型**:AWS IoT Core、Azure IoT Hub、涂鸦智能;开源原型 ThingsBoard、EMQX > **一句话定位**:让百万级不可靠、低功耗、随时掉线的设备**安全地连上来、数据收上来、指令下得去**——设备在不在线,业务都照常运转。 --- ## 1. 一句话定位 IoT 平台 = **海量长连接网关 + 设备身份体系 + 一面「设备影子」镜子**。 它和 [实时通讯](../realtime-chat/README.md) 长得像(都是海量长连接),但对话对象从「人」换成了「电池供电、信号飘忽、可能一睡三小时的设备」。核心难点从「消息快」变成了三件事:**设备身份可信、离线是常态不是异常、一条坏指令可能废掉一批真实硬件**。 ## 2. 业务本质:它在解决什么问题 每个做硬件的公司都会撞上同一堵墙:设备卖出去了,**怎么知道它还活着?怎么给它发指令?怎么收它的数据?怎么升它的级?** 自己搭:要处理百万长连接、断线重连风暴、设备认证、消息去重……这是一整个基础设施团队的活。IoT 平台把这层「设备连接的脏活」做成了水电煤:**设备厂商只管做设备和业务,连接、身份、影子、OTA 分发全部外包给平台**。商业模式按连接数 / 消息量计费——本质是卖「设备连接的规模化能力」。 ## 3. 核心需求与约束 **功能性需求:** - [ ] 设备注册与身份认证(一机一密) - [ ] 海量设备长连接接入与状态管理(在线 / 离线 / 心跳) - [ ] 遥测数据上行(采集 → 管道 → 存储) - [ ] 指令下行(且要处理「设备不在线」) - [ ] 设备影子 / 数字孪生(云端保存设备状态镜像) - [ ] 规则引擎(数据到了 → 触发转发 / 告警 / 联动) - [ ] OTA 固件批量分发(灰度、进度、失败率) **非功能性需求 / 质量属性:** | 质量属性 | 目标 | 为什么对这类系统重要 | |---|---|---| | **连接规模** | 百万~亿级并发长连接 | 常电设备连接 7×24 常挂,电池设备间歇上线——两类都要接 | | **上行吞吐** | 每秒百万级遥测点 | 传感器不知疲倦地报数 | | **指令可达** | 在线秒级、离线补达 | 「远程解锁 / 停机」发不下去业务就停摆(安全联锁必须本地兜底,见 [嵌入式固件](../embedded-device/README.md)) | | **弱网容忍** | 掉线重连是常态 | 2G / NB-IoT / 电池设备,链路天生不稳 | **关键约束(不可逾越的边界):** - 🔴 **设备端资源极小**:协议要轻(不能上重型框架),重逻辑只能放云端。 - 🔴 **设备「睡觉」是省电刚需**:低功耗设备大部分时间不在线,架构必须接受「异步才是常态」。 - 🔴 **设备行为不可控**:老固件、坏时钟、疯狂重连的 bug 设备都会来,平台必须自我保护。 - 🔴 **一机一密是底线**:共享密钥 = 破一台等于破全部。 ## 4. 架构全景图 ``` 百万设备(传感器/网关/家电) │ MQTT 长连接(轻量、支持遗嘱消息) ▼ ┌─────────────────────────────────────────────┐ │ 接入层:MQTT 网关集群(状态外置,水平扩) │ │ · TLS 终结 + 设备认证(一机一密/证书) │ │ · 连接保活、心跳、遗嘱(掉线可感知) │ │ · Topic ACL(设备只能发/订自己的主题) │ └──────────────────┬──────────────────────────┘ ▼ ┌────────────────────┐ │ 消息总线(削峰解耦) │ └──┬──────┬──────┬───┘ ▼ ▼ ▼ ┌─────────┐ ┌──────────┐ ┌─────────────┐ │ 规则引擎 │ │ 设备影子 │ │ 遥测管道 │ │ 过滤/转发 │ │ 状态镜像 │ │ 清洗→时序库 │ │ 告警/联动 │ │ 期望/上报 │ │ →冷存归档 │ └────┬────┘ └────┬─────┘ └──────┬──────┘ ▼ ▼ ▼ 业务系统/告警 应用 API(读影子) 看板/分析/告警 另:OTA 服务 ──分批灰度──▶ 设备(经接入层下发) ``` > 灵魂在于:**应用默认不直接和设备说话,状态类操作一律经「影子」中转。** 应用读影子(毫秒级、永远在线),写「期望状态」;设备醒来后自己对齐。这一面镜子,把「设备时灵时不灵」和「业务要稳定」解耦了。 ## 5. 组件职责 - **MQTT 接入网关**:维持海量长连接,认证、保活、ACL。*为什么需要*:连接管理是整个平台最贵的资产。注意长连接网关**天然有状态**(连接、会话、订阅关系都在它身上)——把会话与路由外置到共享存储、让网关实例本身可替换,才能水平扩容;滚动升级也要分批踢连接 + 排空,否则就是自己制造重连风暴。 - **设备身份 / 注册中心**:每台设备的证书 / 密钥、生命周期(激活 / 禁用 / 注销)。*为什么需要*:设备身份是一切安全的根;支持「单台吊销」才能处置被攻破的设备。 - **消息总线**:接入层和业务层之间的缓冲。*为什么需要*:百万设备同时上报的洪峰,绝不能直接打到数据库上——先入队,同 [通知系统](../notification-system/README.md) 的削峰思路。 - **设备影子(Digital Twin)**:云端为每台设备维护一份 JSON 状态:`reported`(设备上报的)+ `desired`(应用期望的)。*为什么需要*:见决策 1——它是整个平台最重要的抽象。 - **规则引擎**:「温度 > 80 → 告警 + 关阀」这类逻辑的声明式配置。*为什么需要*:让业务方不写代码就能处理设备数据,平台的可玩性来自这里。 - **遥测管道 + 时序存储**:清洗、降采样、按时间分层存储。*为什么需要*:遥测数据量大、按时间查、极少改——天生的时序负载。 - **OTA 分发服务**:管理固件版本、分批推送、统计升级成功率、失败熔断。*为什么需要*:对百万设备,一次全量推送 = 一次豪赌;分批灰度是唯一负责任的姿势(设备侧配合见 [嵌入式设备固件](../embedded-device/README.md))。 ## 6. 关键数据流 **场景一:遥测上行(数据的主干道)** ``` 1. 设备采样,攒批后经 MQTT 发布到自己的遥测主题 2. 接入网关校验 ACL → 转投消息总线(立刻返回,不等落库) 3. 遥测管道消费:清洗(剔坏点/补时间戳)→ 写时序库 4. 规则引擎并行消费:命中「温度>80」→ 触发告警 + 下发关阀指令 ── 全链路异步:洪峰被总线吸收,任何下游慢了都不影响设备上报 ``` **场景二:指令下行(影子解决「设备在睡觉」)** ``` 1. 用户在 App 点「把空调调到 26 度」 2. 应用写影子的 desired:{temp: 26} → 立刻返回「指令已下达」 3a. 设备在线:平台推送影子变更,设备执行,回写 reported:{temp: 26} 3b. 设备在睡觉:什么也不发生——设备下次醒来主动拉影子, 发现 desired ≠ reported,自己对齐,再回写 reported 4. 应用对比 desired 与 reported 即可知道「指令生效了没」 ── 应用面对的永远是「秒回的影子」,而不是「时灵时不灵的设备」 ``` **场景三:OTA 批量灰度(别把百万设备一起推下悬崖)** ``` 1. 上传新固件 → 圈定目标设备群(型号 × 当前版本) 2. 第一批 1%:下发升级通知 → 设备分块下载 → 回报升级结果 3. 观察窗口:成功率 ≥99.5% 才放下一批;失败率超阈值自动熔断暂停 4. 10% → 50% → 100%,每批都有观察窗;离线设备醒来后补收通知 ``` ## 7. 数据模型与存储选择 核心实体:`设备`(身份、型号、固件版本);`影子`(desired / reported);`遥测数据`;`规则`;`OTA 任务`。 | 数据 | 存储类型 | 为什么 | |---|---|---| | 设备注册表 / 身份 | 关系型 | 强一致、事务(激活 / 吊销不能含糊) | | 设备影子 | 文档型 / KV | 每设备一份 JSON,按设备 ID 读写,高频小对象 | | 遥测数据 | 时序库(热)+ 对象存储(冷) | 按时间写入和查询、量大、不可变;过期降采样归档 | | 连接路由(设备连在哪台网关) | 内存级 KV | 下行指令要秒查「它在哪」,掉线要秒清 | | OTA 固件包 | 对象存储 + CDN | 大文件、不可变、百万设备并发下载 | ## 8. 关键架构决策与权衡 ⭐ **决策 1:直接向设备发指令,还是经过设备影子?⭐** - 直发:链路短、实时性好;但设备离线就失败,应用要自己处理重试、超时、状态不明。 - 影子中转:应用写「期望」,设备醒来自己对齐;代价是多一层抽象和最终一致(生效时间不确定)。 - **取向**:**状态类默认走影子**。IoT 世界里「离线」是常态,影子把离线兜成了「稍后生效」而不是「失败」。但注意边界:**影子适合「目标状态」(空调 26 度),不适合「一次性动作」(重启、拍一张照、开一下门)**——动作要走带 TTL 的指令通道,过期作废、不补执行;把动作建模成 desired,设备睡三小时醒来执行一条过期指令,是经典事故。硬实时控制(工业联锁)则根本不该依赖云端下行。 **决策 2:MQTT,还是 HTTP?** - HTTP 轮询:设备端最简单;但保持在线要不停轮询——费电、费流量、指令延迟高。 - MQTT 长连接:双向、轻量(固定报头最小 2 字节,单条消息的真实开销主要看主题名长度——所以 topic 要设计得短)、有遗嘱消息、天然发布订阅。 - **取向**:设备通道用 MQTT(或同类轻协议),「感知设备掉线」这条能力只有长连接给得起;HTTP 只适合「一天报一次数」的极低频设备。但别高估感知速度:**掉线感知延迟 ≈ 1.5 × 心跳间隔**,心跳越短感知越快、也越费电——低功耗设备的「在线状态」天然是模糊的,业务别按「秒级精确在线」去设计。 **决策 3:设备直连平台,还是经过边缘网关?** - 直连:架构简单,每台设备一个连接、一份身份。 - 网关代理:BLE / Zigbee / 有线传感器没有 IP 能力,只能挂在网关下;网关还能本地预处理、断网缓存。 - **取向**:两者都要支持。**网关下的子设备也要有独立身份和影子**(而不是网关「代表」它们),否则换网关 = 所有子设备重置,同 [工业边缘网关](../industrial-edge/README.md) 的南向接入。 **决策 4:遥测全存,还是边缘先算?** - 全量上云:数据完整、后悔药充足;但带宽和存储成本随设备数线性爆炸。 - 边缘预聚合:上报量降 10~100 倍;代价是丢了原始明细,「当时没想到要的数据」再也拿不回来。 - **取向**:分层——**告警判断尽量前移(边缘 / 设备),明细按需采集(默认降采样,出问题的设备临时开全量)**。 ## 9. 规模化与瓶颈 - **第一个瓶颈:单网关连接数上限。** → 破解:会话状态外置 + 连接分片,路由表放共享 KV,加机器就能扩。 - **第二个瓶颈:重连风暴。** 区域断网恢复后,几十万设备同一秒杀回来,认证服务先倒。→ 破解:设备端随机退避重连(固件里就要写好!)+ 接入层限流排队。 - **第三个瓶颈:时序库写入。** → 破解:按设备 ID 分片、批量写入、热冷分层、过期降采样。 - **第四个瓶颈:影子读写热点。**(应用侧高频轮询大设备群)→ 破解:影子变更改推送(订阅事件流)、批量查询接口、缓存。 ## 10. 安全与合规要点 - **一机一密 / 一机一证**:设备身份唯一、可单独吊销;密钥出厂烧录进安全存储,绝不共享。 - **最小权限 Topic ACL**:设备只能发布 / 订阅自己 ID 下的主题——防止一台被攻破的设备伪造全网数据或窃听别家。 - **传输加密**:全链路 TLS;低端设备算力不够也至少要有报文级签名。 - **僵尸网络是真实威胁**:Mirai 用「默认密码」组建了几十万台的僵尸网络——设备认证的松懈会变成对全互联网的攻击。 - **合规**:设备数据可能含个人隐私(位置、作息、健康),按属地隐私法规存储与授权;某些行业(电力、医疗)有数据不出域要求。 ## 11. 常见误区 / 反模式 - ❌ **用 HTTP 轮询做设备通道** → ✅ 长连接 + 推送;轮询在电池和蜂窝流量面前不可持续。 - ❌ **应用直接对设备发指令,不管在不在线** → ✅ 影子中转,离线 = 稍后生效,不是失败。 - ❌ **遥测数据直接写关系库** → ✅ 消息总线削峰 + 时序库;关系库扛不住也不适合。 - ❌ **全部设备共享一个接入密钥** → ✅ 一机一密,可单独吊销。 - ❌ **固件升级全网一把推** → ✅ 分批灰度 + 成功率熔断。 - ❌ **设备重连不做退避,断网恢复集体冲锋** → ✅ 随机退避写进固件;平台侧限流兜底。 ## 12. 演进路线:MVP → 成长期 → 成熟期(不同阶段怎么设置) | 阶段 | 规模量级 | 怎么设置(具体) | 此时该操心什么 | |---|---|---|---| | **MVP** | 千台以内 | 直接用云厂商 IoT 服务(按量付费),或单机 EMQX + 时序库;影子可先用简单 KV | 先跑通「连接→上报→下发」闭环,别自建接入层 | | **成长期** | 十万台 | 开源自建(EMQX 集群 + 总线 + ThingsBoard 类平台)或继续云服务;补齐 OTA 灰度、规则引擎、告警 | 重连风暴、时序数据成本、影子抽象是否统一 | | **成熟期** | 百万~亿级 | 接入层多地域部署、设备就近接入;时序分层存储;OTA 平台化(版本矩阵 / 灰度策略);自动化设备风控 | 单地域故障不影响全网、成本(连接+存储)、被攻破设备的隔离速度 | ## 13. 可复用要点 - 💡 **「影子」是应对不可靠参与方的通用模式**:给时灵时不灵的一方立一面「永远在线的镜子」,把同步调用变成状态对齐——对接不稳定的第三方系统同样适用。 - 💡 **desired vs reported 分离 = 声明式思想**:应用声明「要什么」,执行方自己收敛,Kubernetes 的期望状态模型是同一哲学。 - 💡 **洪峰入口先入队**:接入层只做「收 + 认证 + 转投」,一切处理异步化——同 [通知系统](../notification-system/README.md)。 - 💡 **灰度 + 熔断是所有「批量改变现实世界」操作的标配**:推固件、发营销、改配置,一个道理。 - 💡 **身份颗粒度决定安全上限**:能吊销单台设备,才能只损失单台设备。 ## 🎯 随堂检验 --- ## 参考原型与延伸阅读 > 本模板基于以下**真实开源项目**与**官方文档**整理。 **🔧 开源原型(可直接读代码):** - [thingsboard/thingsboard](https://github.com/thingsboard/thingsboard) — 最流行的开源 IoT 平台:设备接入、遥测、规则引擎、看板一体,本模板全景图的完整开源对照。 - [emqx/emqx](https://github.com/emqx/emqx) — 高并发 MQTT 接入层的开源标杆(单集群千万级连接),体现「接入层集群 + 无状态扩展」。 **📖 官方文档:** - [AWS IoT Device Shadow 服务](https://docs.aws.amazon.com/iot/latest/developerguide/iot-device-shadows.html) — 设备影子(desired / reported / delta)的定义性文档,对应本模板第 6 节场景二与决策 1。 - [MQTT 协议官网](https://mqtt.org/) — 协议规范与生态入口:轻量头部、QoS、遗嘱消息为何为弱网设备而生。 --- > 📌 一句话记住 IoT 平台:**它是「百万台不可靠设备」与「要求稳定的业务」之间的缓冲层——身份让设备可信,长连接让状态可感,影子让离线不再是失败。所有设计都在回答:『设备不在线的时候,业务怎么照常转?』**