简介:这是一份能源管理数据中台(物联网中台/平台)的需求设计说明文档,共24页/约7000字,面向需要搭建物联网数据采集、设备接入与应用对接平台的产品、研发及架构人员。资源以doc文档形式提供,包内仅1个文件,大小718KB。文档围绕基于Main-Flux开源物联网平台构建数据中台展开,重点说明高并发设备接入(1W+规模)、mqtt-server集群部署、Redis实时存储与MySQL集群持久化、微服务动态扩展、设备类型与采集脚本自由扩展、采控分离及控制指令插队等核心设计,同时给出管理端功能模块(首页统计、设备类型管理、运营商管理、项目管理等)、中台API、界面原型、数据字典、技术规范与性能要求。整体框架从项目概况、系统框架、功能模块到数据字典逐层递进,便于直接用于需求评审或二次开发设计参考。目前已有542人学习下载,适合作为物联网中台建设前期的需求分析与方案设计模板。
1. 数据中台不只是消息转发,更是设备接入的边界
做能源管理类项目时,很多团队会把物联网平台当成一个“设备消息转发器”来做——设备上报,应用消费,中间加个鉴权就算完事。但实际落地两年后会发现问题全堆在接入层:设备型号越接越多、通讯协议从 MQTT 扩展到 NB-IoT 和 LoRaWAN、同一路 485 总线上的采集任务越来越多,每个应用都得自己处理协议解析和设备状态维护,改动一段报文解析就要动业务代码。这个资源里的能源管理数据中台需求设计文档,核心要解决的是两件事:一是把设备接入、协议转换、数据规整这一层从业务系统里剥出来,让上层应用只需要通过 API 操作设备和拿数据;二是把设备管理、采集调度、控制插队、授权隔离这些平台能力做成可复用的中台服务。文档基于开源物联网平台 Mainflux 二次开发,技术栈是 Go 语言微服务架构,支持 HTTP、MQTT、WebSocket、CoAP 等多协议接入,并明确规划了设备类型动态扩展、采控分离、集群部署和 Redis 实时数据存储等关键设计。这篇博文从工程落地角度逐章拆解这份需求设计文档,不讨论产品愿景,只讲设备接入层怎么建模、采集线程池怎么调度、控制指令怎么插队、Redis 实时库怎么防穿透,以及这些设计在真实部署中的优缺点。
2. 选型 Mainflux 背后的逻辑,以及中台要改的是哪几层
2.1 为什么选 Mainflux 而不是从零搭建或选商用 IoT 平台
文档里明确说基础是基于开源物联网平台 Mainflux 二次开发。这个选择比较务实。从零搭建物联网中台要处理的不只是数据收发,还有设备影子、通道状态、规则引擎、用户角色权限、多租户隔离这些系统性问题。商用物联网平台在私有化部署和多网隔离的能源场景下,授权费用和二次开发自由度往往不理想。Mainflux 的好处在于几个设计取向刚好契合这份文档的场景。
Mainflux 的定位是设备与应用之间的消息中枢,而不是完整的产业物联网应用平台。它不替你做能源管理、设备运维或者计量计费,而是把物联接入层做成可复用的基础设施,业务开发者只需要通过北向 API 消费数据。这种边界划分恰恰是数据中台的核心思路。技术栈上,Go 语言的并发模型适合大量设备连接和消息转发,微服务架构便于按需拆分部署,原生支持 MQTT、CoAP、HTTP、WebSocket 且能协议互转,在单机场景下的消息吞吐和连接数表现都足够支持万级设备规划。
2.2 中台改造的三个层次
在 Mainflux 基础上做二次开发,不能只是简单增加几个 API,需要分三层去动代码。第一层是接入层改造,原生的 Mainflux 支持 MQTT 和 CoAP 接入,但文档要求支持 LoRaWAN 和 NB-IoT 等无线协议接入,并且新增通讯协议通过管理端配置指向微服务的方式动态扩展。这意味着不能把协议适配写死在网关服务里,而是要抽象出统一的协议路由层。第二层是设备管理层改造,原生 Mainflux 的设备模型是扁平的结构,只有设备 ID、Key 和 metadata,但中台文档要求设备有设备类型、采集脚本版本、485 通道参数、GPS 信息、量程范围等描述,设备通道需要存储实时值,这需要新增一整套设备类型定义、通道模型和采集脚本管理机制。第三层是数据存储改造,Mainflux 默认使用 Postgres 存关系数据和元数据,使用时序数据库存储消息流,但文档明确要求实时数据库用 Redis 存储所有设备状态和通道值,同时需要考虑持久化以应对异常情况。
2.3 改造边界的取舍建议
我看了这份文档的功能模块划分后有一个整体判断:管理端、后台、中台 API 的三段式拆分等于把设备接入做成一个带界面的开放平台。管理端主要面向三类角色:平台运维人员查看集群状态和服务器指标;运营商管理员管理项目、设备和授权;开发人员查看设备接入状态、升级采集脚本。后台里最核心的是设备管理微服务、数据采集微服务、授权管理微服务三个模块,其中数据采集微服务是整个中台的技术难点。中台 API 面向业务应用和第三方系统,提供设备实时值、设备控制、设备信息管理三类接口。
提示:在改造 Mainflux 时,建议保留原生 Northbound API 和 Southbound API 的边界,把新增的设备通道模型建立在这两套 API 之上,不要直接推翻原生消息链路,否则升级 Mainflux 社区版代码时会非常痛苦。
从实施角度来讲,这份需求设计文档的功能点已经细到可以做开发排期和工程量评估了,但有几个点文档没有展开,需要在开发前补齐:一是管理端角色与运营商多级结构的关系模型,二是采集脚本的上传、版本管理和运行沙箱设计,三是 Redis 持久化方案选型,四是集群模式下 MQTT 消息路由规则。这些在后续章节会逐一说清楚。
3. 设备接入层的核心设计:多协议路由与设备类型动态扩展
3.1 设备类型模型与通道定义
文档里反复提到设备类型、通道、采集脚本这几个概念,并把 DI 通道、DO 通道、AI 通道、AO 通道、485 通道作为设备类型的核心属性。这种设计实际上定义了中台设备模型的基本范式:设备类型是设备能力的抽象模板,通道数量定义了设备的点位集合,采集脚本则是设备类型的数据解析逻辑。设备管理微服务需要新增数据库表来存储设备类型、采集脚本、设备信息和设备通道信息,这比原生的 Mainflux 设备模型多了一层关键的语义。
设备类型和通道的关系可以用这样的数据模型来描述:一个设备类型包含多个通道定义,每个通道有通道类型、信号范围上限、信号范围下限、量程上限、量程下限等属性;一个具体设备在接入时根据设备类型自动创建对应的通道实例。设备通道的实时值存储在设计上有讲究,文档明确要求所有设备状态和通道值存储采用 Redis,这不仅仅是性能考虑,也是为后续的控制下发和状态同步提供统一的数据视图。
设备类型管理的操作细节也要注意。添加设备类型时,需要提交设备类型的基础信息、支持的通讯方式、采集脚本及版本信息。删除设备类型时需要先判断是否存在该类型的设备实例,如果存在则提示并支持一键删除。采集脚本升级时的失败回滚策略,文档给出了明确方案:升级前备份原脚本,升级成功后删除原脚本,失败则恢复原脚本。
3.2 多协议接入的路由设计
文档把通讯接入设计为可动态扩展的微服务集群,不同通讯方式可以拥有独立的微服务集群,设备加入平台时通过通讯协议路由指向对应的微服务进行采集。新增通讯协议方式需要支持动态扩展,通过管理端配置新增通讯类型以及指向微服务后,即可完成通讯方式的扩展,即可添加对应通讯方式的设备并完成采集。
这个设计在 Mainflux 原生架构之上增加了更高层抽象。Mainflux 原生的协议适配器各自监听不同的端口,但设备接入后统一定义为 Things 并通过 Channel 进行访问控制。中台的需求是在此之上增加一层协议路由,让不同通讯方式的设备可以走不同的微服务实例。实际开发中,这个协议路由往往通过 NATS 的 Subject 规则引擎实现。设备上报数据时,Gateway 根据设备的通讯协议和微服务路由配置,将消息发往对应的 NATS Subject,设备管理微服务订阅该 Subject 统一处理。这样做的好处是新增通讯协议时只需要部署新的微服务实例,并在管理端做路由配置,不需要改动平台核心代码。
关于通讯方式和设备采集的关系,文档还提到了南向接口和北向接口的区分。设备管理是南向接口,应用管理是北向接口。南向接口包括设备接入、采集配置、固件升级等;北向接口包括应用 API、实时数据推送等。中台 API 作为对接接口提供高并发支持,满足大量并发的设备数据请求。
3.3 采集脚本的扩展机制
数据采集服务的核心能力之一是设备类型动态扩展,不仅仅是主动上报式的设备类型,还包括透传采集类型设备的动态扩展。文档明确说明,透传采集的设备需要能够根据设备类型调用对应的 Python 采集脚本进行采集、解析,并完成设备通道值的更新。设备类型可以动态扩展,完成设备类型拓展以及采集脚本上传后,即可添加对应的设备类型进行采集。
Python 采集脚本的执行环境设计需要考虑隔离性。比较成熟的做法是在数据采集微服务中内置一个脚本执行器,脚本只能通过中台提供的 SDK 接口与设备进行串口读写、Socket 通讯和通道值更新,不允许访问宿主机文件系统和网络栈。脚本执行时的资源限制,比如运行时长、内存占用、异常捕获,都需要在脚本执行器层面控制。文档中要求采集脚本在线查看,主要在管理端实现脚本内容的可视化展示,便于运维人员检查设备类型定义是否正确。
脚本版本管理的核心是回滚能力。文档对升级脚本的过程有明确要求:升级采集脚本的过程中需要考虑升级过程失败的情况,所以需要进行原脚本备份,升级成功后原脚本删除,失败原脚本恢复。实际操作中,脚本版本表的字段应包括主版本号、次版本号、脚本文件路径、上传时间、上传人、脚本描述、状态字段,状态字段标记为“待上线”、“已上线”、“已回滚”三种状态。采集脚本依赖的设备类型信息、通道数量、采集参数等,在升级前需要校验兼容性。
3.4 采控分离与控制指令插队机制
文档中这部分在整个需求设计里技术含量最高。平台支持采集和控制的主题分离,并支持同一路 485 线性采集过程中有下发控制指令的情况下,暂停下一设备采集,完成控制后恢复采集的功能。这是一个典型的工业场景需求:一条 485 总线上挂了多台 DTU,DTU 下挂多台智能仪表设备,采集线程按照顺序依次轮询总线上的设备,但控制指令的优先级高于采集指令,必须插队执行。
具体实现上,数据采集服务需要建立透传设备采集线程池,通过透传类设备的 IP 来控制采集线程池的线程,将同一 IP 的透传类型设备加入到同一线程,线程通过设备类型对应的采集脚本来主动进行设备的数据采集。同一台 DTU 的多个设备放到同一个线程里,同一路 485 总线上同一时刻只会有一个采集任务在执行,避免总线冲突。
控制指令插队需要考虑线程安全。文档要求设备控制的响应必须控制在 3 秒内。实现方案是:采集线程在调用串口写指令前先检查控制指令队列,如果队列非空则立即暂停当前的采集循环,转而执行控制指令。控制指令执行完毕后,恢复采集线程继续从暂停位置开始轮询。这个机制可以用 Go 语言的通道和定时器实现,也可以用一个带优先级的任务队列来管理。
提示:采集线程的暂停是发生在指令级别,而不是设备级别。不要用关闭线程的方式暂停采集,会导致 TCP 连接和串口资源被反复重建,效率极低。正确的方式是设置采集暂停标记,让采集循环在下一轮设备轮询前检查标记。
设备采集使能控制是另一个贴近工程需求的设计,支持采集使能的动态控制,可以随时关闭对应设备的采集。这个设计其实是在满足现场运维场景:当某个设备离线或者报故障时,运维人员可以在管理端单独关闭该设备的采集,而不影响同一条总线上的其他设备。设备采集使能状态可以放在设备通道表的“通道状态”字段上,也可以单独建一张设备采集使能表。
从调度策略上看,485 总线上的采集顺序、采集周期、超时时间也是需要考虑的重要参数。文档虽然没有给出具体的调度算法,但实际开发中需要在设备类型里增加“采集时延时间”配置,同时考虑动态调整采集周期。
4. 数据链路与存储层设计:Redis 通道值、时序数据库与冷热归档
4.1 两级存储架构
中台的数据存储方案是清晰的两级架构。第一级是 Redis 实时数据层,存储所有设备的实时通道值、设备在线状态、采集时间戳等。第二级是关系数据库与文件存储层,关系数据库承担业务数据存储,时序数据库承担历史数据存储。
设备实时通道值在 Redis 中的存储可以遵循这样的规范:使用 Hash 存储设备通道值、使用 Hash 存储设备状态信息,使用 Hash 记录设备的最后上线心跳。每个设备在线状态和通道值变化更新,延迟需要控制在 200ms 以内。设备在线率统计涉及的在线状态、最近 30 天设备在线率、设备在线时长、设备接入时间等数据,可以在 Redis 中维护一个设备状态集,然后在关系数据库中定时落库。
从需求文档看,设备离线判断也需要在 Redis 层实现。MQTT 服务收到设备的遗嘱消息时,在 Redis 中更新设备离线状态;如果设备连接异常断开,则通过 connack 超时检测机制,在 Redis 中标记设备离线。设备离线判定不要依赖 MQTT 心跳本身的超时时间,因为心跳失败到判定离线需要时间,会导致在线率统计不准。建议在 Redis 中维护设备的最后心跳时间,由数据采集微服务定时检测超时设备并更新在线状态。
持久化问题要重点考虑。Redis 作为实时设备数据层,必须要考虑异常掉电时的数据恢复问题。文档明确要求实时数据库采用 Redis 存储并需要考虑持久化以应对异常情况。常见的方案有三种:RDB 快照、AOF 日志、RDB+AOF 混合模式。在设备通道值场景下,RDB 快照即可满足需要,但建议在 Redis 集群版本上开启 AOF 并配置为 everysec 策略。
4.2 消息总线与数据流
设备数据从接入到存储的链路,在文档的设计下应该是这样的:
MQTT Broker(通过 mqtt-server 集群部署)接收设备上报,将消息转发到设备接入微服务,设备接入微服务解析消息并转换成统一的内部事件格式,通过 NATS 事件总线进行消息分发。设备数据订阅服务从 NATS 中消费数据事件,更新 Redis 中的设备实时通道值;时序数据写入服务同时将原始数据写入时序数据库,用于后续的历史查询和统计分析。
数据中台的消息流转涉及系统事件总线 NATS 和规则引擎,文档中明确说明“复杂的消息处理,基于系统事件总线 NATS,通过规则引擎,根据时间数据流进行事件触发”。NATS 在这个架构中的作用是解耦生产者与消费者,让设备接入、设备管理、数据存储、统计分析等微服务之间可以异步通信。
使用 NATS 时需要对 Subject 规则做好规划。比如:设备接入服务发布设备原始数据到 DATAPOINT 等主题;数据采集服务消费数据并更新到 Redis;时序数据服务消费原始数据并写入时序数据库;设备状态变化事件单独用一个 Subject 发布。通配符规则建议符合以下规律:超过 10 万个设备的平台,Subject 规划不当会造成 NATS 路由表巨大,消息性能下降。
4.3 时序数据库的改造与冷热归档
文档要求框架原有的时序数据库进行修改以适配业务需要。以 Mainflux 默认时序库 TimescaleDB 或 Prometheus 这类方案来说,需要把设备通道值、采集时间戳、设备标签、通道编号建立合适的表结构。历史数据的保留策略和降采样策略也要在设计时考虑。
设备通道历史数据有两个读写特点:实时性要求高的是设备本身和最近几分钟的数据,低频查询的是长期归档数据。文档虽然没有具体说明历史数据的存储要求,但结合对 Redis、MySQL 集群的明确要求,可以把冷热数据分离作为归档表设计的核心思路。将时序数据分为前 90 天的热数据和超过 90 天的冷数据,热数据保留在时序数据库,冷数据定期导出到低成本存储或归档表。归档表的设计可以参考这个 SQL 结构:
CREATE TABLE device_channel_archive ( id BIGINT PRIMARY KEY AUTO_INCREMENT, device_id VARCHAR(64) NOT NULL, channel_id VARCHAR(32) NOT NULL, channel_value DECIMAL(12, 4) NOT NULL, collect_time DATETIME NOT NULL, archive_date DATE NOT NULL COMMENT '分区字段,按天存储' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 PARTITION BY RANGE (TO_DAYS(archive_date)) ( PARTITION p20240101 VALUES LESS THAN (TO_DAYS('2024-01-02')), PARTITION p20240102 VALUES LESS THAN (TO_DAYS('2024-01-03')) );归档表的字段设计需要注意几个细节。channel_value 的类型要根据设备量程精度来选择,一般 DECIMAL(12, 4) 就够用;如果设备传感器的精度高于 4 位小数,可以调整到 DECIMAL(14, 6)。archive_date 字段专门用于分区键,查询时不建议直接依赖该字段,而是通过创建时间进行范围过滤。归档表数据的查询频度远低于实时库,需要建联合索引。
归档流程也可以放到数据采集微服务中定时执行。常见做法是:每月 1 日凌晨 2 点,数据采集服务执行一个定时任务,将时序数据库 90 天前的数据批量导出到归档表。如果归档数据量达到亿级,按月分区会导致数据倾斜,建议按天分区,然后由定时任务合并旧分区。
4.4 MySQL 集群与表结构设计的取舍
文档对关系数据库的要求比较具体:运营商、项目、设备等数据要求采用 MySQL 的集群版本或其他关系数据库的集群版本进行部署。考虑到 MySQL 在物联网平台中的广泛应用,一般选择 MySQL Group Replication 或者使用云厂商的 MySQL 高可用集群。
设备管理相关的核心表至少包括:运营商表、项目表、设备表、设备类型表、设备通道表、采集脚本表、设备分配关系表、授权信息表。设备表字段按文档要求至少需要设备 ID、设备名称、所属运营商 ID、所属项目 ID、通讯方式、设备类型 ID、设备描述、GPS 信息、网络 IP、网络端口、串口地址、串口波特率、串口停止位、串口校验位、设备接入时间、最后更新时间等字段。
由于数据库需要存储大量设备,关系数据库中 MySQL 集群需要考虑分区分表策略。设备表建议按运营商维度分片,或者按设备接入时间的年份分片。在分片策略上,可结合业务场景多做权衡论证,如果查询负载在项目维度上集中,也可以按项目维度分片。
5. 授权管理与多级运营商的隔离策略
5.1 数据级授权与租户隔离
文档用大篇幅描述了运营商-项目-设备三级授权体系。运营商是平台的第一层租户,每个运营商可以有多个项目,设备归属于项目和运营商。管理端功能里多次出现“每个运营商只能查看到自己以及自己所属的下级运营商的项目”的描述,这是数据级隔离的要求。
授权管理微服务需要加入运营商、项目、设备的授权管理控制,支持通过授权对运营商下的项目、设备进行 API、采集的访问控制。运营商接入项目、设备授权上限后无法进行添加、接入。授权管理微服务还要实现黑名单机制,运营商授权时间到期后采集服务需要能够阻止该运营商所属的设备与平台建立链接。
数据级授权的实现思路是:在设备接入层和 API 层分别增加授权校验环节。设备连接时先校验运营商授权状态,如果授权过期或超出设备上限,则拒绝连接或下发黑名单指令让设备主动断开。应用 API 调用时校验项目授权和应用授权,确保上层应用只能访问授权范围内的设备数据。
5.2 运营商账号体系与访问控制
文档明确运营商有两种混合登录方式,运营商名称加用户名加密码作为登录验证机制,需要做到数据级控制,即根据运营商加用户的级别来决定用户可访问的管理端菜单、菜单内的功能以及可访问数据。
运营商账号级别分为三级:超级管理员(admin)、管理员(级别 2)、查看员(级别 3)。级别 2 的管理员可以添加设备及设备控制测试,可以添加项目,可以分配设备;级别 3 的查看员可以查看设备、项目的状态。每个运营商的 admin 账号在创建运营商时同步生成,且不可删除。
从安全角度,管理端的接口层面需要设计一套细粒度的权限控制框架。管理端菜单权限建议由平台方定义一组模块编码,运营商账号表里存储有权限的模块编码列表,用户登录后返回可访问的菜单和功能列表。控制类操作,比如设备控制、设备固件升级、项目删除,需要有额外的操作日志记录。
5.3 管理端在线 API 测试功能的设计
管理端提供了 API 在线查询和 API 在线测试功能,文档特别强调“API 在线测试所产生的数据由独立的测试数据库进行处理,不影响正式数据库的数据”。这个设计很细致,在管理端内嵌一个 API 测试工具,实际上就是一个轻量级的集成调试工具。
API 测试工具的数据库隔离实现比较简单:中台 API 层增加一个测试环境标志,当请求头携带测试模式标志时,实时数据读写走独立的 Redis 实例,业务数据存储走测试数据库。这样设计能保证联调测试和生产数据互不污染。
在线 API 功能还包含完整的 API 列表查询,每项 API 都提供详细的说明、入参、出参信息,便于第三方业务系统对接时查阅。这对系统的可集成性非常有帮助。同时也要注意 API 鉴权机制,建议对应用接入采用 API Key 方式,为上层的每个第三方应用分配独立的 API Key,确保不同应用的数据隔离。
6. 落地排错与性能验证的实战技巧
6.1 集群部署的常见问题与排查策略
文档明确要求支持 mqtt-server 集群部署,核心服务需要设置为热备,至少需要 3 台 ECS 节点。使用 EMQ X 或 Mosquitto 作为 MQTT 服务器时,集群模式下需要注意共享订阅配置。设备连接通过负载均衡分发到不同节点,但同一设备的连接路由需要保持一致。如果使用 EMQ X,可以启用 MQTT 会话保持和共享订阅,确保消息在多节点下不重复、不丢失。
集群模式下快速定位节点异常可以从几个方向排查:先看 MQTT 节点的连接数和订阅数情况,正常情况各节点连接数应该比较均衡,如果出现某个节点连接数为零而其他节点非常高,检查负载均衡的健康检查配置;再看消费组积压情况,如果 NATS 中某个 Subject 的消费速率跟不上生产速率,说明数据采集微服务的消费能力不足,需要扩容消费者实例。
建议运维人员定期检查 MQTT 客户端的重连频率和服务端日志。设备的重连频率过高通常说明网络不稳定或负载过高,需要开发者关注,此时应当在设备端和服务端分别抓包定位。
6.2 采集脚本与透传链路的断点排查
采集脚本执行失败时,需要快速判断是脚本本身的逻辑问题还是设备通信问题。建议在脚本执行器里加入分步日志,记录从创建 Socket 连接、发送读取指令、等待响应、解析报文到更新通道值的每一步耗时。这个思路来源于文档中“业务逻辑函数需要把每个步骤耗时打印出来”的规范要求。
示例代码:
import time import json import socket class ModbusRtuCollector: def __init__(self, device_config): self.ip = device_config['ip'] self.port = int(device_config['port']) self.slave_id = int(device_config['device_id']) self.timeout = float(device_config.get('timeout', 3)) def read_registers(self, start_addr, quantity): start = time.time() try: sock = socket.create_connection( (self.ip, self.port), timeout=self.timeout ) # 组装 Modbus RTU 读保持寄存器报文 cmd = self._build_read_cmd(start_addr, quantity) sock.send(cmd) resp = sock.recv(256) elapsed_ms = (time.time() - start) * 1000 print("[collector - read_registers] elapsed_ms=%d" % elapsed_ms) return self._parse_response(resp) except socket.timeout: print("[collector - read_registers] timeout") raise finally: sock.close()这段代码在采集脚本的关键路径上打印了耗时,通过分析耗时长的是建连、等待还是解析,可以快速定位问题。网络层故障通常在 create_connection 阶段抛异常,超时通常是设备未响应。这里的设备 id 是设备在平台中的唯一标识,linux 下端口对应真实 DTU 监听端口。对于熟手来说,建议再加一步:将采集脚本的 stdout 和 stderr 重定向到单独的文件,避免日志和业务日志混在一起。
6.3 Redis 实时库的误用与排查
设备实时值场景 Redis 的误用主要集中在三类。第一类是 key 数量膨胀,每个设备的每个通道单独存储一个 key,导致 key 数量级达到十万甚至百万级。应该优先使用 Hash 结构来聚合存储通道值。第二类是持久化策略不当,设备离线状态和实时通道值这类数据修改频繁,RDB 全量快照会导致 CPU 飙高;可以在 RDB 基础上开启 AOF,将 appendfsync 配置为 everysec。第三类是热点 key 问题,如果管理端首页同时刷新所有设备的在线状态,会对单个 hash key 产生较高的读负载。建议管理端读取实时状态时做分页拉取,也可以利用 Redis Cluster 的 hash tag 来做节点级的负载均衡。
排查 Redis 性能问题优先使用下面几个命令:
redis-cli --latency -h <redis_host> -p 6379 redis-cli --bigkeys redis-cli --stat--latency 查看服务延迟波动,--bigkeys 检查存在大 key 的 hash 或 zset,--stat 持续输出 Redis 的实时状态指标。结合这三个命令的输出来判断是网络问题、数据结构设计问题还是内存容量问题。
6.4 冷热数据分离的验证方法
对于冷热数据归档的验证,常见做法是写一个统计脚本对比归档前后的查询响应时间。归档之前,热数据查询 30 天跨度的通道数据需要在毫秒到秒级完成;归档之后,同样的查询应该从归档表走,响应时间会略有增加,但这个代价换来的是热表体积的稳定和写入性能的稳定。更重要的验证指标是看热库中数据量的增长速度,如果热数据库的数据量一直在增长不下降,说明归档任务没有正常执行,需要排查定时任务的日志。
验证归档表数据的完整性可以写一个简单的 SQL 对比总记录数:
SELECT COUNT(*), device_id, MIN(collect_time) AS min_time, MAX(collect_time) AS max_time FROM device_channel_archive WHERE archive_date = '2024-06-01' GROUP BY device_id ORDER BY device_id;这条 SQL 的作用是验证归档数据的覆盖范围和记录数量。实际使用中可以对每个 device_id 抽查几个通道点位的数值,和源时序数据库中的原始记录对比。如果 min_time 和 max_time 之间有断档,通常是因为归档任务执行期间数据采集服务也在写入数据,产生了数据丢失或者归档任务本身有漏数据的问题。
6.5 基于需求文档做验收测试清单的要点
文档虽然整体是一份需求设计说明,但已经包含了大量可以进行验收测试的功能点。比如设备在线率、设备接入时延、控制响应时延、采集脚本升级回滚、数据级权限隔离等条目都可以直接转化为测试用例。测试过程中最重要的一条是:数据中台的验收一定要用真实设备和模拟流量同时跑,模拟流量的比例不超过 20%,否则压力测试做出来的性能指标很难真实反映恶劣的现场网络环境。
在搭建测试环境时,也可以按照文档的技术规范用 Gofmt 做代码格式化,用 GoLand File Watcher 自动跑 goimports,并在每个文件头部写上创建者、时间和功能描述。这些规范看似边缘,但在多团队协作的中台项目里,代码风格统一是排查问题和 code review 效率的基石。
本文还有配套的精品资源,点击获取