物联网架构师的两难
消费互联网架构师面对的是“用户请求”,而物联网架构师面对的是“设备生命”。
用户请求超时可以重试,用户不开心但不会投诉到工信部。但换电站的机械臂指令迟到了500毫秒,电池可能卡死在充电仓里,整个站点的车辆会排起长队;医院监护仪的连接中断30秒,护士站报警系统直接拉响红色警报。
这是我在2021年参与某换电网络平台设计时的真实认知冲击。我们习惯的“高并发”是万人秒杀,但物联网的“高并发”是 百万设备永久在线 + 秒级心跳保活 + 指令毫秒必达 + 数据洪峰不可预测 。每一台设备都在以固定的节奏向你报告存在,你不能假装它们不在。
本案例将以 吉利易易换电 和 某智慧园区 两个真实场景为蓝本,还原一个高可用物联网平台从0到1的设计全过程。我们不追求“亿级连接”的神话——那是华为云、AWS的战场。我们关注的是:当你需要从零搭建一个支撑数万至百万级设备、要求99.99%可用性的物联网平台时,每一步应该踩在哪里,以及如何避免那些让你通宵救援的坑。
一、核心矛盾:物联网架构的“不可能三角”
在动笔画架构图之前,必须先理解物联网平台独有的三个核心矛盾。任何架构决策,本质上都是在三角中寻求动态平衡。
矛盾一:连接持久性 vs. 资源有限性
消费互联网的连接是短暂的——用户打开App,请求数据,断开连接。物联网的连接是 永久在线 的。一台换电站的设备365天×24小时与云端保持心跳,一个传感器的连接时长以年为单位。
这意味着:你不能用“会话”的思维管理设备,必须用“生命周期”的思维 。每一次设备重连,都是一次对认证、订阅、状态恢复的完整考验。
矛盾二:消息可靠性 vs. 实时性
MQTT协议定义了三个QoS等级,但现实是:QoS 1(至少一次)可能产生重复消息,QoS 2( exactly once)的交互开销在高并发下可能拖垮Broker。
更棘手的是:指令必须可靠,但延迟必须极低 。换电指令迟了200ms,流程卡顿;计费消息丢了,直接经济损失。这不是“最终一致性”能敷衍的场景。
矛盾三:数据洪峰 vs. 成本约束
每台换电站每秒上报电池电压、温度、SOC、SOH等十余个指标。当2000座换电站同时运营,每秒消息量可达 15万TPS 。
你可以选择把所有数据原封不动存入时序数据库,然后看着云账单每个月翻倍。你也可以选择在边缘做过滤聚合,但必须承担开发复杂度和数据丢失的风险。
架构师的第一课 :接受这个三角无法完美解决,只有取舍。
二、决策框架:从业务反推架构
在接触任何技术组件之前,我们必须先回答四个问题:
Q1:设备规模上限是多少?
- 易易换电:2027年规划2000座换电站 × 每站50个传感器 + 运营车辆终端 → 约15-20万并发设备
- 智慧园区:2000+异构设备,协议包括Modbus、OPC UA、私有TCP
决策 :MQTT Broker必须支持 十万级长连接 ,且集群扩容对业务无感。
Q2:实时性要求多高?
- 换电指令:端到端延迟 < 500ms(含设备响应)
- 园区报警:传感器触发 → 平台告警 < 2秒
决策 :消息中间件必须支持毫秒级延迟,不能引入批处理或长轮询机制。
Q3:数据丢失容忍度?
- 计费消息:0丢失
- 设备遥测:可容忍少量丢包,但趋势数据必须完整
决策 :核心交易链路使用QoS 1 + 客户端确认;遥测数据使用QoS 0,但边缘缓存兜底。
Q4:部署模式约束?
- 易易换电:公有云,弹性伸缩
- 园区项目:部分客户要求私有化、离线部署
决策 :架构必须 云原生兼容私有化 ,核心组件均有开源替代品。
这四个问题的答案,直接决定了技术选型的边界。
三、架构全景:分层解耦的四级体系
基于上述约束,我们设计一个 四层物联网平台架构 。这不是教科书式的分层,而是经过实战检验的、能够应对“从百级到百万级”平滑演进的结构。
┌─────────────────────────────────────────────────────────────┐
│ 应用层 (业务服务) │
│ 设备管理 │ 规则引擎 │ 数据API │ 告警中心 │ 计费 │
└─────────────────────────┬───────────────────────────────────┘
│
┌─────────────────────────▼───────────────────────────────────┐
│ 消息处理层 (消息中枢) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ RocketMQ │ │ Pulsar │ │ Kafka │ │ ← 根据场景选型
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────┬───────────────────────────────────┘
│
┌─────────────────────────▼───────────────────────────────────┐
│ 接入层 (MQTT Broker) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ EMQX Cluster / 阿里云MQTT / RabbitMQ MQTT插件 │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────┬───────────────────────────────────┘
│
┌─────────────────────────▼───────────────────────────────────┐
│ 边缘层 (Edge Gateway) │
│ 协议适配 │ 数据过滤 │ 本地缓存 │ 断网续传 │
└─────────────────────────────────────────────────────────────┘
设计哲学 :每一层只做自己职责范围内的事,层与层之间通过标准协议解耦。接入层不懂业务逻辑,业务层不关心设备IP。
四、接入层设计:把“连接”本身当作产品
物联网平台的第一道门槛是 设备接入 。很多团队轻视这一层,认为“不就是用个EMQX吗”。但根据我们的经验, 80%的线上故障发生在接入层 ——不是EMQX不够稳定,而是使用姿势错误。
4.1 Broker选型:三个方案的真实权衡
方案A:全托管云服务(阿里云MQTT、Azure IoT Hub)
易易换电选择了阿里云MQTT版。核心决策逻辑:
- 优势 :无需运维集群,自带全球接入点,TLS证书管理开箱即用
- 代价 :单条消息成本约0.15元/百万条,私有化部署不可行
- 适用 :业务爆发期,团队没有专业中间件运维能力
方案B:开源EMQX自建集群
某智慧园区项目选择了EMQX Enterprise。决策逻辑:
- 优势 :单节点百万连接,私有化交付可行,Erlang/OTP的容错架构极其稳健(有客户创下 1770天不间断运行 纪录)
- 代价 :需要专职运维熟悉Erlang VM调优,集群脑裂恢复有学习成本
- 适用 :对成本敏感、需私有化交付、有中间件团队
方案C:RabbitMQ MQTT插件
Kamea平台从Azure IoT Hub迁移到Kubernetes后,选择了RabbitMQ作为MQTT Broker。决策逻辑:
- 优势 :一套集群同时解决MQTT接入和内部微服务通信,技术栈统一
- 代价 :RabbitMQ的MQTT插件在高并发场景的性能弱于EMQX,万级连接尚可,十万级需慎重
- 适用 :中小规模、希望简化技术栈的团队
我们的建议 :
- 初创期(0-1万设备) :用云托管MQTT服务,把钱花在业务验证上
- 成长期(1万-10万设备) :评估自建EMQX,培养中间件能力
- 成熟期(10万+设备) :必须自研或深度定制,成本效益最优
4.2 连接管理的魔鬼细节
选完Broker只是开始。真正让你失眠的是以下三个问题:
问题1:设备ID如何路由?
负载均衡器必须确保 同一设备的请求始终落到同一Broker节点 ,否则持久会话状态需要跨节点同步。
实战方案 :一致性哈希路由,设备ID作为哈希键。
public int getServerIndex(String deviceId) {
return Math.abs(deviceId.hashCode()) % serverCount;
}
但在动态扩缩容时,一致性哈希只能减少影响,无法完全避免重哈希。 妥协方案 :扩容窗口期允许少量设备重连,业务侧做好断线重连机制。
问题2:心跳保活怎么设计?
设备每60秒发送一次心跳,Broker更新Redis中的设备状态。但如果10万台设备同时心跳,Redis的写入压力骤增。
实战方案 :
- 心跳时间 打散 :设备注册时下发一个随机偏移量,避免整点风暴
- 状态存储 分级 :活跃状态存在Broker内存,离线持久化存入Redis
- 感知 延迟容忍 :设计上允许5-10分钟的心跳延迟,不必实时更新
问题3:离线消息积压怎么办?
持久会话模式下,设备离线期间的消息会被Broker缓存。但如果某设备离线一周,积压百万条消息,恢复连接时可能瞬间冲垮设备或网络。
实战方案 :
- 设置 队列最大长度 (如100条),超限则丢弃最早消息
- 重要指令(如固件升级)单独通道,不混入普通遥测队列
五、消息处理层:物联网的“脊椎”
如果说接入层是感官,消息处理层就是脊髓——所有数据在此汇聚、分流、缓冲、路由。
5.1 消息中间件的选型分水岭
物联网场景对消息中间件提出了三个传统互联网不常见的苛刻要求:
- Topic数量极大 :每个租户/每个设备可能独占Topic,Kafka在5000个Topic后性能显著下降
- 扩容速度要求高 :业务波峰波谷明显,扩容必须分钟级,不能有小时级的数据Rebalance
- 消费模型多样化 :既有大数据批量消费,也有AMQP队列模式
华为云IoT的选型答案 : Apache Pulsar 。
- 计算存储分离 :扩容只需增加Broker节点,无需迁移数据
- 天然支持百万级Topic :存储层与Topic解耦
- 统一消费模型 :同时支持Kafka风格的流和RabbitMQ风格的队列
易易换电的选型答案 : 阿里云RocketMQ 。
- 与阿里云MQTT原生集成,消息流转零代码
- 顺序消息、事务消息能力成熟
- 运维托管,无需自建
Kamea平台的选型答案 : RabbitMQ 。
- 技术栈统一,一套集群解决南北向流量
- 足够支撑数万级设备
我们的建议 :
不要为了技术先进而选型 。如果你已经在云上,就用云厂商的消息队列产品——这不是技术决策,是成本决策。如果你必须自建:
- < 5万设备 :RabbitMQ足够,简单可靠
- 5万-20万设备 :Kafka或RocketMQ,注意Topic数量规划
- > 20万设备 :认真考虑Pulsar,它的架构优势在高规模下不可替代
5.2 消息契约:从第一天就标准化
比选型更重要的,是定义一套统一、可扩展的数据格式。
反面案例 (某实际项目):
"1,25.5,60.1,0,1,2025-02-12 10:23:45"
解析代码需要维护一份“第0位是啥、第3位是啥”的文档,新设备接入时文档已过时,只能反编译旧代码。
正面案例 (推荐模板):
{
"deviceId": "SN-2025-E001",
"timestamp": 1707819825000,
"messageType": "telemetry",
"payload": {
"temperature": 25.5,
"humidity": 60.1
},
"context": {
"rssi": -67,
"firmware": "v2.1.3"
}
}
三个必须遵守的原则 :
- 自解释 :字段名必须有业务含义,禁止缩写
- 版本化 :messageType隐含版本号(如
telemetry.v1 )
- 向后兼容 :只增字段,不改语义,不删字段
成本代价 :每条消息多传几十个字节,一年增加数万元云成本。
收益 :新设备接入时间从3天压缩到2小时,数据团队不需要反复问“这个字段是什么意思”。 这笔账怎么算都值 。
六、边缘层:被低估的架构主战场
很多物联网架构师把边缘网关当作“可选项”。这是 致命的认知偏差 。
以智慧园区项目为例:2000个异构设备,部分户外节点距离核心机房数百米,网络链路不稳定。如果所有数据都直接发到云端:
- 实时性崩盘 :部分节点延迟超过500ms
- 成本崩盘 :4G流量费每月数万元
- 可靠性崩盘 :网络抖动即丢数据
边缘网关不是锦上添花,是必须品 。
6.1 边缘网关的三大核心职责
职责1:协议适配——把“方言”翻译成“普通话”
工业现场是协议丛林:Modbus、OPC UA、Profibus、CAN bus,以及各种私有协议。
实战方案 :
- 驱动层插件化架构,每种协议封装为独立Driver
- 私有协议采用“抓包-解析-建模”逆向工程,建立帧头识别+自定义校验模块
真实数据 :某项目通过边缘层协议适配,将串口通信错误率从5%降至0.01%以下。
职责2:数据治理——在源头削减数据量
设备上报频率可能是1秒一次,但99%的场景下你不需要1秒级精度。
实战策略 :
- 过滤 :滑动窗口去重,连续相同数值只保留变化
- 聚合 :区域内多传感器计算均值、最大、最小,上传聚合值而非原始值
- 脱敏 :位置信息、设备序列号在边缘完成匿名化
成本效益 :某园区项目部署边缘预处理后, 云上存储成本下降70% 。
职责3:断网续传——给脆弱网络兜底
边缘节点与云端网络不可能100%可靠。断网期间的数据如何处理,是区分“玩具级”和“工业级”的分水岭。
实战方案 :
- 本地时序存储 :SQLite或轻量级TSDB,容量可配置(如保留7天)
- 断线检测 :基于心跳超时自动切换本地模式
- 续传策略 :网络恢复后按FIFO顺序上传,并标记“补传”标识
- 容量保护 :存储达到阈值时,按“时间优先丢弃最旧数据”
某换电站项目数据 :每月因网络波动触发断网续传约15次,平均中断时长8分钟, 数据零丢失 。
6.2 边缘网关的高可用设计
边缘节点往往部署在无人值守的机柜,硬件故障不可避免。
可用性设计清单 :
- ☑ 双电源模块,主备自动切换
- ☑ 关键接口(网口、串口)冗余
- ☑ 节点健康自检,定期上报心跳
- ☑ 故障转移:主节点宕机,备用节点30秒内接管IP和连接
教训 :某项目忽略边缘网关的磁盘寿命,消费级SD卡在户外高温环境下3个月损坏。 必须使用工业级SSD或eMMC 。
七、存储层:分而治之,各得其所
物联网数据是典型的 混合负载 。把时序数据、关系数据、文件数据塞进同一个数据库,是架构腐化的开始。
我们采用 三类存储分离策略 :
| 数据类型 |
特征 |
存储选型 |
关键考量 |
| 时序数据 (遥测、状态) |
海量、写多读少、按时间范围查询 |
时序数据库 (InfluxDB/TimescaleDB/ openGemini) |
数据降采样策略、自动过期 |
| 元数据 (设备信息、用户、租户) |
关系型、需事务、低频变更 |
关系型数据库 (PostgreSQL/MySQL) |
读写分离、分库分表预设计 |
| 文件数据 (固件包、日志、截图) |
大文件、不常读、需CDN加速 |
对象存储 (MinIO/S3/OSS) |
生命周期管理、多版本控制 |
7.1 时序数据库的选型陷阱
时序数据库是物联网存储的核心,也是最容易“踩坑”的地方。
常见错误 :使用普通关系库存储时序数据,三个月后查询慢如牛车。
真实对比 :
- MySQL 5.7:10亿条传感器数据,按时间范围查询平均耗时 28秒
- TimescaleDB(PostgreSQL插件):相同数据量、相同查询 1.2秒
选型建议 :
- < 1亿点/天 :TimescaleDB(复用PostgreSQL技术栈,无需引入新组件)
- 1亿-10亿点/天 :InfluxDB企业版或阿里云TSDB
- > 10亿点/天 :openGemini(华为云开源)、VictoriaMetrics
关键决策 : 预先设计降采样策略 。原始数据保留7天,5分钟聚合保留30天,1小时聚合保留1年。没有降采样的时序数据库,3个月后必然成为成本黑洞。
八、高可用设计的“冗余思维”
物联网平台不能有单点故障——这句话谁都会说,但真正做到位的不多。
8.1 集群架构的两种模式
模式一:全互联(Full-Mesh)
EMQX经典的Mnesia全互联集群:
- 所有节点两两互联
- 每个节点持有全量路由信息
- 客户端连接到任意节点,均可路由到目标
优点 :会话状态实时同步,故障切换秒级无感 缺点 :节点数超过10个时,广播风暴风险
模式二:Core-Replicant(分层集群)
EMQX 5.0引入的新架构:
- Core节点 :全互联,负责数据持久化、事务处理
- Replicant节点 :无状态,从Core复制数据,不参与事务
优点 :可扩展至百节点,运维简化 缺点 :Replicant与Core之间有网络依赖
实战建议 :
- 中小规模(<10节点):全互联架构,简单可靠
- 大规模(>10节点):Core-Replicant,牺牲少量复杂度换取无限扩展
8.2 容错设计的“崩溃哲学”
EMQX基于Erlang/OTP构建,其容错哲学值得借鉴: Let it crash 。
这不是鼓励程序崩溃,而是 通过进程隔离,让崩溃的影响最小化 。
实战应用 :
- 每个设备连接封装为独立进程/协程,一个设备的内存泄漏不影响其他设备
- Supervisor树监控所有工作进程,崩溃即重启,业务无感知
- 杜绝“万能异常捕获”——除非你能真正处理,否则不要吞掉错误
你的架构里是否有这样的隔离机制? 如果没有,一个设备的异常可能拖垮整个Broker。
8.3 可观测性:高可用的“眼睛”
没有可观测性的高可用是自欺欺人。
物联网平台必须实时监控的五个黄金指标 :
- 连接数 :当前在线设备数,同比/环比变化
- 消息吞吐 :入/出 TPS,15分钟趋势
- 延迟分布 :端到端指令延迟的P95、P99
- 队列积压 :Broker中待处理消息数量
- 设备错误率 :连接拒绝、认证失败、超时重连
工具栈 :
- 指标:Prometheus + Grafana
- 日志:ELK或 Loki
- 链路追踪:SkyWalking(华为云IoT已集成至Pulsar)
真实案例 :某换电平台通过监控发现,每日18:00-19:00的指令延迟会从50ms飙升至800ms,排查后发现是计费系统的批量结算任务占用了全部数据库连接。 没有可观测性,这种“慢性病”可以潜伏数月 。
九、演进案例:从PaaS托管到Kubernetes自建
让我们看一个完整的架构演进实例—— Kamea平台 的迁移之路。
阶段一:Azure IoT Hub托管(0-1)
- 快速上线,3个月完成MVP
- 成本:按设备量付费,初期每月仅数百美元
- 痛点:客户要求私有化部署时无法满足
阶段二:自建RabbitMQ + Kubernetes(1-10万设备)
- 迁移策略:逐项审计Azure服务,寻找开源替代
- IoT Hub → RabbitMQ MQTT插件
- Service Bus → RabbitMQ队列
- Azure Functions → Knative + KEDA
- 成果:同一套架构可部署在AWS、Azure、私有机房
- 代价:团队需学习Kubernetes,初期运维效率下降
阶段三:多云分发(10万+设备)
- 基础设施即代码:Terraform + OpenTofu
- 客户自助部署:通过配置文件选择云厂商
- 成本效益:单设备月成本降低42%
启示 :没有永远正确的架构,只有当前阶段最合适的架构。Kamea在初期选PaaS是对的,在成长期弃PaaS也是对的。
十、架构决策复盘清单
如果你的团队正在启动一个物联网平台项目,这份清单可以作为第一次架构评审的输入。
接入层
- [ ] Broker选型是否匹配未来2年的设备规模?
- [ ] 是否有设备ID一致性哈希路由策略?
- [ ] 心跳风暴是否已通过时间打散避免?
- [ ] 持久会话队列长度是否有限制?
- [ ] TLS证书是否有自动化轮转机制?
消息层
- [ ] 是否已定义设备上报的标准化JSON Schema?
- [ ] 核心指令链路是否使用QoS 1+客户端确认?
- [ ] 是否存在Topic数量失控风险?
- [ ] 消息积压是否有监控告警?
- [ ] 跨AZ/跨地域流量成本是否已估算?
边缘层
- [ ] 是否所有设备都强制经过边缘网关?
- [ ] 协议适配是否插件化架构?
- [ ] 数据过滤聚合策略是否已配置?
- [ ] 断网续传是否经过混沌工程测试?
- [ ] 边缘硬件是否满足工业级环境要求?
存储层
- [ ] 时序数据、元数据、文件数据是否分离存储?
- [ ] 是否已规划数据降采样与过期策略?
- [ ] 数据库连接池是否有限制?
- [ ] 备份恢复是否定期演练?
高可用
- [ ] 是否存在任何单点故障?
- [ ] 节点故障是否秒级自动切换?
- [ ] 是否有全链路压测机制?
- [ ] 可观测性是否覆盖五个黄金指标?
- [ ] 应急预案(Runbook)是否每个值班工程师都能看懂?
十一、结语:连接之外的价值
当我们完成了接入、消息、边缘、存储、高可用,我们拥有了一个“合格”的物联网平台。
但用户不会为“合格”付费。
平台的价值,永远在连接之外 :
- 是换电站从人工巡检变成远程诊断,运维成本下降60%
- 是园区空调根据人流密度自动调节,能耗下降25%
- 是机械设备预测性维护,非计划停机减少70%
架构师的任务不是连接设备,而是让数据流动,让价值发生。
这是物联网的终极浪漫——你写的每一行代码,都在把物理世界的不确定性,装进数字世界的确定性模型里。每一次指令送达,都是一次对熵增的微小抵抗。
设计一个健壮的物联网平台是典型的 System Design 挑战,它不仅考验你对 消息队列 和 容器化 等技术栈的理解,更考验你在实际业务约束下的决策能力。希望这篇来自实战经验的架构复盘,能为你提供有价值的参考。如果你有更多关于物联网或后端架构的问题,欢迎来 云栈社区 与其他开发者交流探讨。