资讯详情

开源物联网数据采集平台UNIHH-IOT架构设计与落地经验

📅 2026/10/13 8:55:34 | 华诺云谱 👁 阅读
开源物联网数据采集平台UNIHH-IOT架构设计与落地经验
接手过物联网平台类项目的人多半都经历过这样一幕设备已经接进来了数据也收到了但想梳理清楚“现在线上到底有多少台设备、多少台异常、昨天整条产线的平均能耗是多少”却要在数据库里翻半天。设备接进来只是第一步怎么让数据有序地流动、存储、呈现才是真正拉开差距的地方。UNIHH-IOT这套开源物联网数据采集与管理平台就是围绕这件事设计的把分散的、协议各异的设备数据统一收上来清洗好存得下看得懂。这套系统适合正在做物联网方案选型的技术负责人、负责设备接入的后端工程师以及想把“数据采集”这件事做成标准化产品的团队。文章不会只讲概念会把每一层架构设计的原因、参数估算过程、容易踩的坑全部摊开来讲方便你直接拿去应对自己手头的物联网项目。1. 系统设计的起点把数据链路当成一条生产线1.1 从业务场景反推架构需求任何物联网平台立项之前先别急着选数据库、画架构图要把业务场景想清楚。我自己习惯的做法是列三个问题要接哪些设备数据要用来做什么谁在看这些数据以最常见的场景为例智慧园区里有几千个传感器采集温度、湿度、水电表读数工厂里有几十台数控设备需要采集主轴转速、振动、报警状态环境监测站每隔几秒就上报一条PM2.5数据。这些设备来自不同厂商有的走MQTT有的只支持Modbus RTU有的则是HTTP定时上报数据格式也各不相同。把需求汇总之后你会发现所谓“数据采集与管理平台”核心就四件事接入、采集、存储、展示。但每件事往下拆都很深。接入要解决多协议适配和认证问题采集要解决高并发写入和网络抖动问题存储要解决时序数据量爆炸的问题展示要解决实时刷新和响应速度的问题。UNIHH-IOT最终确立的设计目标很朴素一个平台多种协议统一数据模型一套管理界面。设备接入之后业务方不需要关心底层是Modbus还是MQTT看到的就是标准化的设备属性、事件、服务三类数据。这个思路和传统工业SCADA不同它更强调松耦合和平台化后续每增加一种新设备只是新增一个适配器而不需要改平台核心。1.2 顶层架构的分层逻辑与选型理由整个平台按照数据流向拆成四层设备接入层、消息管道层、存储计算层、应用管理层。设备接入层是边界负责所有协议的接入、解析、认证。这一层最容易犯的错误是把业务逻辑写在接入服务里比如在MQTT消息处理回调里直接读写数据库。初期设备量少的时候没问题一旦规模上来数据库连接池马上被打满。消息管道层承担削峰填谷的任务。所有上报数据先进消息队列再做后续的解析和入库。为什么一定要加这一层因为设备上报是突发的而存储系统希望写入是平稳的。举个例子如果有1万台设备每5秒上报一条消息写入速率就是每秒2000条早晚高峰可能翻倍。如果应用层直接同时写库和做规则判断任何一个环节抖动都会导致数据积压甚至丢失。存储计算层做的事情是两个时序数据存储、规则引擎计算。时序数据单独存这部分后续我会详细讲。规则引擎则负责把流入的数据做实时判断比如温度超过80度就告警命中的消息再推送到通知服务。应用管理层是用户最终看到的设备管理、数据看板、告警记录、系统配置。这一层不直接接触设备协议所有数据通过接口从底层拿。这样分层的价值在于每一层都可以独立扩展接入层扛不住的时候加节点存储层不够的时候换更强的时序数据库应用层加功能不影响设备侧。选择MQTT作为主设备接入协议是因为它在低带宽、弱网场景下表现稳定QoS机制能给不同程度的消息可靠性保证。HTTP上报适合低频业务数据Modbus多见于工业存量设备这两类通过网关适配器也能平滑接入。整个平台选用的技术栈都是开源生态里验证过的东西不依赖特定商业产品。2. 数据采集层的硬核细节从连接建立到数据标准化2.1 设备接入的Topic规划与认证机制设备接入第一件事是定Topic规范。Topic是MQTT协议里最需要提前设计的东西改起来牵扯所有设备端固件成本极高。UNIHH-IOT采用的Topic结构如下unihh/{productKey}/{deviceName}/up 设备上行数据 unihh/{productKey}/{deviceName}/down 平台下发指令 unihh/{productKey}/{deviceName}/event 设备事件告警、故障 unihh/{productKey}/{deviceName}/status 设备状态变更productKey是产品唯一标识同型号设备共用一个productKeydeviceName是设备唯一编号。这样设计的好处是权限可以精确到单台设备而且数据天然按产品维度分区后续做统计报表时查询非常方便。认证机制上推荐使用一机一密方案。每台设备出厂时烧录唯一的productKey、deviceName、deviceSecret连接时用这组凭证计算动态签名。平台校验通过后才允许订阅和发布。在很多项目里出现过设备凭证硬编码在固件里、一个泄露导致整个项目凭据泄光的情况所以强烈建议增加动态签名和过期时间戳。Topic的订阅权限也值得注意。普通设备只允许订阅自己的Topic不允许订阅其他设备的数据管理类设备或边缘网关才开放跨设备订阅权限。否则防火墙挡得住外部攻击内部设备互相订阅数据照样能把消息管道打爆。2.2 物模型采集数据标准化的关键一步设备接入之后最让人头疼的是数据格式千奇百怪。有的设备上报{t:25.6,h:60.1}有的上报{temperature_c:25.6,humidity_percent:60.1}如果平台层不对数据做标准化后续所有查询、告警、展示逻辑都会写成一堆判断语句维护成本极高。UNIHH-IOT参考了大量物联网平台的设计经验引入了物模型这一套数据抽象方式。物模型把设备数据分为三类属性、事件、服务。属性是设备某个时刻的状态值比如当前温度、当前开关状态事件是设备主动上报的异常或里程碑信息比如“电机过载”事件服务是云端对设备下发的能力调用比如“打开阀门”指令。每次上报都会走统一的校验器把原始数据转换成标准物模型消息{ productKey: pk_standard_001, deviceName: dev_0001, timestamp: 1700000000000, type: property, data: { temperature: 25.6, humidity: 58.2, switch_state: 1 } }这里有个细节容易被忽略设备上报时间戳和平台接收时间戳要分开存。设备时间可能是本地时钟经常不准如果直接用上报时间排时序排序会乱套。平台接收时间从消息队列里拿到的时间为准同时保留设备端原始时间字段用于判断设备时钟偏差。2.3 采集侧的容错、心跳与断线缓存设备网络环境远比服务器复杂弱网、掉线、断电都常发生。平台侧必须预设好容错措施否则稳定性和“稳定”两个字沾不上边。心跳机制用的是MQTT协议自带的但很多项目栽在心跳间隔的配置上。心跳设太短比如10秒设备一多 broker 每秒要处理大量PINGREQ消息白白消耗CPU心跳设太长比如10分钟设备实际掉线了平台要等很久才能感知。UNIHH-IOT默认推荐心跳60秒broker侧设置服务端允许的最大会话过期时间30分钟。对于低功耗NB-IoT设备可以放宽到几小时一次心跳但必须配合遗嘱消息机制。遗嘱消息是MQTT里很有用的特性。设备上线时先发送遗嘱比如“这台设备异常掉线了”正常下线时发送清除遗嘱的报文。如果设备是断网、断电方式掉线broker会自动替设备发布遗嘱消息。平台订阅状态Topic之后就能第一时间感知设备异常离线触发告警和工单。断线缓存是边缘侧方案。设备本地使用环形缓冲区把最近几百条数据先写本地存储网络恢复后按时间戳顺序补报。平台侧收到补报数据时要按平台时间戳重新排序因为补报的消息可能和实时消息穿插在一起处理顺序错乱会导致图表出现毛刺。这一点很多平台都处理得不好监控图上突然冒出一个历史峰值就是没做时间戳对齐。3. 数据管理层的存储与流转设计3.1 数据量估算与消息队列的削峰作用在设计存储方案之前先做一个具体的数据量估算避免拍脑袋选型。假设平台接入1万台设备每台设备每5秒上报一条消息消息体平均大小按512字节计算每秒数据条数10000 / 5 2000 条每小时数据条数2000 × 3600 7,200,000 条每天数据条数7,200,000 × 24 172,800,000 条每天数据体量172,800,000 × 512B ≈ 88 GB也就是说光原始数据一天就有接近90GB的写入量。实际业务中还要考虑消息头、索引开销情况只会更多。这样的写入压力让应用服务直接写关系型数据库显然不合适。消息队列在这里起到的作用是缓冲和削峰。上游设备数据先进Kafka写入速率是波动的比如整点上报高峰可能到每秒5000条低谷可能每秒几百条。存储层只需要按照自己稳定的速率从Kafka消费写入不必跟着设备上报节奏走。Kafka的Topic分区数量建议按写入速率估算单分区顺序写吞吐大概在每秒千条量级2000条业务数据分配至少8个分区预留双倍余量到16或24个分区即可。3.2 存储选型时序数据库、关系库与缓存的明确分工物联网平台的数据有非常明显的特征随时间持续产生、数据量大、主要用于趋势查询。这种数据用通用关系库强撑写索引和聚合统计一旦数据量过亿查询性能断崖下跌。UNIHH-IOT的数据存储设计采用三分方案时序数据使用时序数据库存储保留原始数据30天元数据设备信息、产品模型、用户配置存MySQL实时状态最近一条设备状态缓存放Redis时序数据库的保留策略可以这样写CREATE DATABASE iot_telemetry KEEP 30 DURATION 1d REPLICA 1;KEEP 30表示数据保留30天DURATION 1d表示数据按天分片。以此为基础再建立降采样任务把5秒粒度数据聚合成5分钟粒度保留一年把5分钟粒度数据聚合成小时粒度永久保存。这样既保证近期查询的精度也兼顾运维想看一年期趋势的需求存储开销能降一个数量级。MySQL里主要放设备注册表、产品物模型、用户权限。这些表数据量不大但涉及事务必须用关系库保证一致性。Redis缓存设备在线状态是因为设备管理页面需要高频刷新在线列表每次实时去查MQTT broker再查库性能太差。设备状态变更时同时更新Redis和一个设备状态Topic页面订阅Topic即可做到秒级刷新。3.3 规则引擎让数据不只是存下来如果平台只是把数据存起来那和一张庞大的Excel表没什么区别。真正的价值在于数据处理自动化也就是规则引擎。UNIHH-IOT的规则引擎做两件事告警判断和消息分发。告警判断的典型场景是温度阈值设备上报数据流进入规则引擎判断当前值是否超过阈值连续几次命中才触发告警。没有规则的平台往往要在应用代码里到处写if-else新接一款设备就要改一次代码。规则配置尽量采用可视化方式底层保存成JSON规则描述。这套规则描述语言支持取值、比较、聚合、时间窗口四类操作数据流入时依次执行。一个典型的规则可以这样表达在10分钟窗口内如果温度平均值大于80度并且持续5个窗口则触发“高温告警”事件。用SQL风格的语法描述如下SELECT deviceName, AVG(temperature) AS avg_temp FROM telemetry WHERE productKey pk_standard_001 GROUP BY deviceName, TIME(10m) HAVING avg_temp 80规则命中之后平台把告警消息重新发到告警Topic由通知服务分发到短信、邮件、WebHook等渠道。这样做的好处是接入层、存储层完全感知不到规则引擎的存在规则挂了不影响数据采集采集挂了也不影响历史数据查询。4. 管理平台的功能拆解与实现要点4.1 设备全生命周期管理管理平台里最基础也最容易被低估的模块是设备管理。很多团队把设备管理做成一张列表那就远远不够了。设备从出厂到报废应该有完整的生命周期状态机未激活、已注册、在线、离线、禁用、删除。未激活状态对应设备虽然录入系统但从未发起过连接已注册是设备第一次连接成功禁用的设备可以记录数据但不触发告警。状态的每次流转都会写入操作日志便于事后审计尤其是工厂项目排查谁把设备禁用了、什么时候禁用的非常重要。设备管理页面上需要展示的信息除了状态还应包括固件版本、最近在线时间、IP地址、信号强度。远程操作区提供指令下发功能选择设备后点击下发重启指令平台将通过下层服务把指令推送给在线设备。这里的关键点是超时处理和回执确认设备不在线时指令要进缓存队列等它上线后自动下发同时要在界面显示“已下发、设备已确认、执行失败”三态。4.2 数据可视化与监控大屏的落地经验数据可视化是用户感知最直接的模块。大屏、数据看板、报表页面三项功能我建议分开做不要全部塞进一个页面。大屏定位是全局状态总览核心是设备总数、在线率、今日告警数、实时数据曲线。图表选型上时序数据用折线图设备分布用地图指标卡用大数字告警信息用滚动列表不要整屏堆满图表。大屏默认的刷新频率建议5秒到10秒一次采用WebSocket推送不要用HTTP轮询否则多个大屏页面同时打开后端接口压力会非常明显。数据看板的定位是日常运营分析查询范围大多是近24小时、近7天。这里要特别注意时间粒度选择用户选近24小时时查询原始5秒粒度数据会非常吃力可以直接查询5分钟聚合数据曲线看起来平滑响应也快。用户选近7天时默认查询小时粒度聚合数据展示效果更稳定。报表页面则适合导出和打印按产品维度汇总数据量、活跃设备数、消息成功率。实现时注意引导用户选择时间范围后再生成避免一打开就全量统计把数据库拖垮。4.3 告警通知链路的降噪设计告警模块能做出来很容易做得好却很难。大部分平台上线第一阶段都遇到同一个问题告警风暴。温度抖动触发告警网络波动触发告警高峰时段告警消息把管理员手机塞满最后所有人对告警麻木。UNIHH-IOT的告警降噪做三件事分级、静默、聚合。分级是把告警分成提醒、重要、紧急三个级别只有重要和紧急才推送短信和电话提醒级别只在站内通知。静默是用户可以设置某台设备或某个规则的免打扰时间段比如下班后不推送非紧急告警。聚合是把同一设备在短时间内重复触发的同类告警合并成一条比如“设备A在14:00至14:10期间触发高温告警5次”而不是发5条独立告警。实现上规则引擎产生的告警消息不直接发送而是进入一个带缓存窗口的聚合模块。窗口时长默认5分钟窗口内相同规则、相同设备产生的告警合并处理。这样既不会漏报也不会被重复告警淹没。5. 常见问题与排查技巧实录5.1 设备频繁掉线与数据延迟的排查路径设备掉线是最常见的现场问题排查顺序我建议遵循“先看协议层再看网络层最后看应用层”。先确认MQTT broker看到的设备连接是否稳定。如果设备显示反复连接断开大概率是心跳间隔设置不合理或设备处在弱网环境导致TCP连接被运营商切断。可以把心跳间隔从60秒调到30秒观察同时检查设备端是否开启了TCP keepalive。如果broker侧连接正常但应用层收到的数据有延迟检查消费链路是否存在瓶颈。Kafka的消费者堆积情况、规则引擎处理耗时都可能影响数据流转。实测中遇到过一种特殊情况设备数据本身到了Topic但规则引擎里配置了跨窗口聚合导致消息被缓存等待窗口结束表现就是数据延迟了几分钟才出现在看板。这不是系统故障是规则逻辑设计问题需要调整聚合策略。5.2 时序数据库写入变慢与存储膨胀写入变慢通常是写入模型和分区设计不当导致的。时序数据库的写入性能有一个原则尽量采用批量写入避免单条写入。消费者从Kafka拉取一批数据后本地攒500条或攒2秒再批量入库写入吞吐能成倍提升。索引是另一个关键点。时序数据库里不要给所有字段建索引每个额外的标签索引都会占用内存和磁盘。设备维度标签保留productKey、deviceName两个就够。查询条件里的温度、湿度等数值字段走字段本身的分区过滤不需要单独建索引。存储膨胀如果明显超出估算首先检查数据重复写入。排查中发现一些消费逻辑没有记录消费偏移量重启后重复消费历史数据导致同一批数据写了两遍。解决办法是消费时开启事务性提交确保数据入库成功后再提交偏移量。还有一点容易被忽略消息队列里的原始数据保留周期。Kafka的日志保留时间默认7天但Kafka本身并不适合当作数据仓库长期保存。及时清理Kafka过期数据并确保时序数据库的保留策略生效能节省大量存储成本。5.3 大量设备同时上报时如何避免告警刷屏在生产环境里最恐慌的事情往往是刚上线半小时监控大屏的告警数字疯狂跳动。常见原因是设备同时上线导致瞬时上报量飙升而规则引擎设置的是单条阈值判断每条数据都命中告警条件。解决思路有两个方向一是在规则引擎里增加时间窗口抑制比如同一设备在5分钟内只产生一条告警二是在设备上线时增加分批上线策略避免所有设备同时连接。这两条建议同时做效果才能稳定。长期运行的IoT项目中设备重启、网络恢复的瞬间最容易触发同类问题提前配置好抑制规则能省去很多半夜被吵醒的麻烦。6. 最后的经验分享这套系统从立项到落地我踩过最大的坑就是前期忽略数据标准化结果后期所有功能都受制于脏数据。物模型设计花的时间越早越多后面省的时间越多。现在每接一类新设备第一件事不是写代码而是先让它输出规范的物模型消息协议解析反而成了次要问题。另一个小技巧分享给正在做类似平台的朋友规则引擎一定要支持在线调试。现场排查问题经常需要往规则里输入一条假数据确认输出的告警格式是否正确。没有调试功能就只能改代码重启效率极低。在管理后台加一个十秒钟能打开的调试入口排查效率能提高一倍不止。UNIHH-IOT目前还在持续优化中下一步计划把边缘网关的离线缓存做得更智能同时在设备数据质量分析上增加更多自动化手段。如果你也在做类似的开源物联网数据采集平台欢迎一起交流踩坑心得。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑