断网续传的缓存容量与补报一致性
支持四象限运行、采用 FOC 驱动方式的 AQMD6008BLS-TE/2 这类设备常装在地下车库、金属机箱或移动平台上,断网是常态。本地缓存与补报做不好会出现两类事故:缓存溢出丢数据,或补报把过期数据灌进时序库。
一、缓存容量按"最坏断网时长"算
取设备每 10s 上报一条合并消息(约 200 字节,示例值):
| 最坏断网时长 | 需缓存条数 | 需缓存容量 | 8 MB Flash 可支持 |
|---|---|---|---|
| 1 h | 360 | 72 KB | 远超 |
| 12 h | 4320 | 864 KB | 约 9 天 |
| 3 天 | 25920 | 5.2 MB | 接近上限 |
| 7 天 | 60480 | 12 MB | 超出,需降采样或覆盖旧数据 |
判据:容量 ≥ 消息大小 × 最坏断网时长 / 上报周期。若目标是不丢 7 天数据,就不能全程 10s 粒度,要改成"近 24h 保细、更早自动聚合"的滚动策略。
Flash 写入还要考虑寿命:8MB 扇区、擦写寿命 10 万次,若每小时整块重写,寿命约 11 年;若每条消息都单独写页,磨损会集中在少数页。做法是环形缓冲 + 批量提交,并按扇区轮转。
二、补报的三个一致性约束
约束一:时间戳有效性。 平台对上报数据的时间戳有范围限制(不得超出未来 24 小时),过期或超前会被拒。补报前必须校验,超范围的样本应丢弃并计数告警,而不是重试刷屏。
约束二:顺序与去重。 补报按原始时间戳排序,且携带样本唯一 ID,云端按 ID 去重。否则断网恢复瞬间的批量补报会与实时数据交错,产生乱序与重复行。
约束三:补报限速。 恢复后一次性灌入数万条会触发限流。按"每秒若干条 + 退避"平滑发送,优先补最近数据。
/* 环形缓存:满则覆盖最旧(保最新数据),并记录丢弃计数 */
#define RING_CAP 4096
typedef struct {
uint32_t ts; uint16_t len; uint8_t data[200]; } rec_t;
static rec_t g_ring[RING_CAP];
static uint32_t g_head, g_count, g_dropped;
void ring_push(rec_t r)
{
if (g_count == RING_CAP) {
g_head = (g_head + 1) % RING_CAP; g_dropped++; }
else g_count++;
g_ring[(g_head + g_count - 1) % RING_CAP] = r;
}
/* 补报前校验时间戳:仅允许 [now-7d, now+24h] */
int ts_valid(uint32_t ts, uint32_t now)
{
return (ts <= now + 86400u) && (ts + 7u*86400u >= now);
}
三、掉电与崩溃安全
缓存必须能扛掉电:写入采用"数据 + CRC + 序号"三段,恢复时扫描最后一个完整记录;提交用双副本标志位,避免半写记录被当成有效数据。补报成功后再推进读指针,且推进操作本身要原子。
四、验证方法
一是断网时长扫描:分别断网 1h/12h/3天,恢复后核对云端行数与本地应有样本数,确认丢弃计数与表格一致;二是掉电注入:在补报过程中随机断电 20 次,确认无半写记录、无重复补报;三是时间戳越界测试:伪造超前与过期样本,确认被拒并进入告警计数而非无限重试。
五、小结
缓存容量按"消息大小×最坏断网时长/周期"算,超预算就滚动聚合而不是硬扛;补报要满足时间戳有效、按 ID 去重、限速发送三条约束;存储层用环形缓冲 + CRC + 原子推进扛掉电。用断网扫描、掉电注入、越界样本三类测试闭环。