工业网关离线补传:缓存容量、顺序与重复数据验收

工业网关的离线缓存应被定义成持久数据协议:哪些测量被接收、能保留多少、何时允许删除记录,以及接收端如何处理补传。网络链路恢复,并不能证明历史数据完整到达。验收必须在采集、本地存储与最终应用之间核对记录身份。

本文讨论遥测数据的存储转发。链路选择和切换请参阅已有的以太网、Wi-Fi与蜂窝故障切换验收指南。命令和执行器操作需要单独的过期与执行策略,盲目补发旧控制命令可能不安全。以下计算为容量估算示例,不是网关性能声明。

定义数据从哪一步开始受保护

画出从读取传感器到服务器提交记录的路径。只保存在RAM中的数值可能在断电时消失;套接字发送成功不代表目标端已持久保存。应将“网关已接收”定义在明确的本地持久化节点,将“已交付”定义在明确的接收端确认节点。

对于轮询传感器,如果网关在持久记录响应之前断电,该次观测仍可能丢失。若产品要求覆盖这一节点之前的保护,源设备需要保留自己的序列或历史记录,或提供其他恢复机制。应说明采集边界,而不是承诺无法观测时间段内的零丢失。

一种可行协议是至少一次传输配合幂等接收:允许重试,同一稳定记录身份只产生一条已提交业务记录。MQTT QoS确认属于协议层确认,本身不能证明下游数据库事务已经完成。MQTT 5.0规定了协议内的QoS与顺序语义。端到端交付仍需要应用层约定,包括代理服务器或消费者故障后的行为。

存储转发遥测流程,包含稳定记录身份、持久队列、重试、接收端事务、确认和对账。
图1:应用层确认闭合持久补传流程;记录身份用于明确重试与对账。图中文字为英文。

同时计算断网容量和恢复后的流量

从每秒记录数、支持的最大记录长度、最大断网时间和实测存储开销开始。计入身份标识、时间戳、封装、索引、日志、压缩整理临时空间和保留策略。闪存标称容量不等于队列可用配额。

raw_backlog_bytes = input_records_per_second
                  * outage_seconds
                  * stored_record_bytes
planned_queue_bytes = raw_backlog_bytes * overhead_and_headroom_factor
recovery_seconds = backlog_records
                 / (durably_acknowledged_records_per_second - input_rate)

以每秒20条、每条256字节、断网8小时为示例,原始积压为147,456,000字节,约140.6 MiB。暂用2倍系数后为281.3 MiB。320 MiB的队列配额可以提供部分余量,但必须用真实存储格式和最差载荷核验。文件系统预留、系统日志和OTA工作区要另行分配预算。

这次断网产生576,000条记录。如果接收端每秒持久确认80条,而新数据仍以每秒20条进入,净消化速度为每秒60条,追平需要9,600秒,即2小时40分钟。如果持续确认速度不高于采集速度,积压永远无法排空。应测量包含TLS、代理服务器、数据库和限流的完整路径,而不是从以太网带宽推算。

明确顺序范围和记录身份

使用稳定身份,例如源ID、数据流代次和单调递增序号。每次重试都保留原身份。规定代次生成和持久化方式,确保重启或恢复出厂设置不会复用接收端仍保留的身份。MQTT报文标识符不适合作为长期应用记录ID。

分别保存源测量时间(若有)、网关采集时间和时间质量。网关启动时可能没有可信墙上时钟;之后的校时不能重写历史序列顺序。本地截止时间使用单调计时。后端应区分迟到历史样本与新鲜测量。

通常需要保证单个传感器数据流内的顺序,而不是网关全部传感器的全局顺序。全局排序可能让一个失败目标阻塞无关源。明确新数据是排在积压之后、走预留实时通道,还是使用加权调度。多通道情况下携带序列信息,并让接收端处理允许的乱序。“最新值”和“完整历史”可能需要不同消费路径。

先在本地提交,再按约定确认删除

采用带完整性检查和恢复扫描的追加日志或事务数据库。批量提交可降低写入开销,但尚未提交的批次仍处在可能丢失窗口内。如果产品在刷写前就宣布接收,应记录这一窗口。测试实际文件系统、闪存器件、驱动和电源电路;软件刷写无法弥补不遵守刷写语义的存储硬件。

SQLite是Linux的一种选择,并非MCU网关的必需项。其原子提交文档解释了事务依赖的假设。在WAL模式下,synchronous设置会改变断电持久性:NORMAL可能在断电后丢失近期已提交事务,FULL则增加逐事务同步。应有意识地选择并验证持久性,并将WAL及检查点空间计入配额。

以下协议草图展示应用层确认。实现时仍需加入认证、有界批次、故障处理和接收端持久唯一性约束:

gateway:
  persist(record_id, payload) before marking locally accepted
  send(record_id, payload)
receiver transaction:
  insert record if record_id is absent
  verify duplicate IDs refer to the same content
  commit
receiver:
  acknowledge(record_id) after the durable commit
gateway:
  persist acknowledgement, then reclaim the queued record

如果服务器已提交但确认丢失,网关会重试同一身份。如果收到确认后、删除本地记录前断电,也可能再次重试。接收端必须容忍这两种情况。除非已经确认连续序列前缀全部提交,否则不能丢弃小于已见最大序号的全部记录,否则乱序形成的缺口会被遗漏。

让缓存满时的行为可见

选择获批准的溢出策略:停止接收、在可能时向源施加背压、丢弃最旧、丢弃最新,或聚合指定数据。不同产品需要不同选择。记录丢失计数及受影响的序号和时间范围;静默覆盖会使后续对账无法进行。即使队列满了,也要预留足够元数据空间用于报告溢出。

只有优先级协议允许时,才将紧急事件与周期遥测分开处理。限制重试退避,并在设备间加入随机抖动,避免现场网络恢复时大量设备同时冲击服务器。为补传设速率预算,保留采集时限、本地界面响应和正常流量。接收端去重保留时间必须覆盖允许的补传与重试周期,包括可能重新引入旧记录的可恢复备份。

在验收中核对记录身份

故障注入 证据 建议验收条件
满输入负载下模拟等效8小时断网 生成、已本地接收及排队ID;实际字节数 在声明的容量和保留窗口内保存全部已接收记录
追加、刷写、处理确认时断电 外部源台账和恢复后的队列 每个已持久接收ID均可恢复,或已在接收端提交
服务器提交后丢弃应用确认 重复传输ID和服务器记录 发生重试;每个ID只有一条业务记录;内容冲突可见
持续采集期间恢复网络 积压下降斜率、接收延迟、CPU及存储负载 积压净下降,实时数据和采集预算仍满足
队列满、写盘失败或存储变为只读 故障状态、丢失范围及重启行为 执行约定溢出与错误策略,不虚报已持久接收
校时与设备重启 身份、代次、序号和时间质量字段 身份不复用,保持要求的数据流顺序

测试台应保存独立的源台账;仅把网关自身队列当作真值,无法发现入队前丢失。比较已接收ID集合与已提交ID集合,再核对载荷哈希、单位和所需的数据流内顺序。区分重复传输尝试与重复业务记录。报告队列最高水位、最旧记录年龄、补传速率和未解决的丢失。

围绕真实应用界定缓存范围

欧蓓特的设备联网服务可以帮助定义采集与服务器消息边界。STM32数据采集与MQTT项目明确将离线存储视为需约定保留容量和补传策略的附加范围。这是相关的已交付案例,但其介绍不代表特定缓存寿命或容量已经验证。

请提供源协议、载荷样例、峰值采集速率、断网要求、存储硬件和服务器确认行为。在接受任何“数据不丢失”要求前,交付范围应包括容量模型、身份结构、溢出策略、持久性假设和对账报告模板。

类似文章