news 2026/9/9 21:54:02

物联网数据压缩实战:从差分编码到存储成本降低70%

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
物联网数据压缩实战:从差分编码到存储成本降低70%

我做了三年多的物联网落地项目,从几十个节点的原型验证,到几千台设备的生产环境,一个感受特别深:硬件成本、流量成本都能靠架构设计抠出来,但存储成本往往是最容易被忽视、又最容易失控的一项。尤其是当你的设备上了量、采了几个月数据之后,数据库账单会以肉眼可见的速度膨胀。我在好几个项目里都遇到过这种状况——数据调取开始变慢、存储费用翻倍、甚至因为磁盘不够被迫清库。

后来我把精力放到数据本身的“压缩”上,配合边缘网关做预处理,效果立竿见影:同一批数据,存储占用降了 70% 以上,查询响应反而快了接近一倍。这篇博文我就想把这套思路完整拆开,从物联网数据的特征分析、算法选型,到端侧与云端的具体实现,再到实测效果和踩坑记录,一次性讲清楚。

这套内容比较适合正在做物联网项目的开发者、做物联网毕业设计的同学,以及被存储成本困扰的运维和架构师。哪怕你没接触过数据压缩,只要懂一点编程基础,按下面的步骤跟下来也能上手。

1. 项目概述:被存储成本逼出来的压缩方案

1.1 一个让我开始折腾压缩算法的真实场景

先说一个让我印象很深的项目。当时我负责一套环境监测系统,设备端用的是 ESP32S3,采集温湿度、PM2.5、电池电压和信号强度这几个量,每 30 秒上报一次。单个节点一天大约产生 2880 条记录,看起来不算大。但部署到 500 个点位之后,一天就是 144 万条记录。那时候我图省事,直接把 JSON 数据原封不动存进了时序数据库,用的还是默认配置。

三个月后一查,存储占用接近 800GB,而且还在以每天好几个 GB 的速度涨。数据库查询开始出现明显的延迟,有时候一个区域的历史曲线要转好几秒。最难受的是,大部分数据其实长得非常相似——同一片区域的温度在几分钟内可能一直稳定在 27.4℃ 和 27.6℃ 之间波动,湿度变化也不大。也就是说,我们花大量存储空间存的,其实是一堆高度重复的数字。

当时我就在想,如果能在数据入库之前做一层压缩,把这些重复信息榨干,是不是存储成本就能大幅降下来?这个念头推动我开始系统研究物联网数据压缩算法,也才有了后面的整套方案。

1.2 物联网数据的特点决定了压缩的收益空间

很多人一听到“压缩”就想到 ZIP、RAR,觉得那是文件压缩的事,跟数据库存储没什么关系。其实数据压缩在物联网场景下的收益,比大家想象中大得多。核心原因在于物联网数据有几个非常明显的特征:

第一,时间序列特性强。绝大多数物联网数据都是按固定间隔采集的时序数据,相邻两条数据在业务含义上往往只差一个采样周期。温度不会忽然从 20℃ 跳到 80℃,电压也不会在一秒内骤变。这个连续性意味着相邻数据的差值很小,非常适合用差分类算法处理。

第二,数据规模增长极快。设备数量一旦过了千级,哪怕每条记录只有几十字节,日积月累也是个恐怖的数字。如果每条设备每分钟上报 10 个字段、每个字段按 4 字节算,一万台设备一天的数据量就能轻松超过 1 亿字节,一年下来就是 40GB 起步。这还只是估算,实际上加上时间戳、设备 ID、协议开销,翻几倍很正常。

第三,周期性规律明显。工业设备、环境监测、农业大棚这类场景,数据的波动往往跟时间周期强相关。比如白天气温高、夜间气温低,这几个大周期叠加在一起,导致数据在更大时间尺度上也存在可预测性。好的压缩算法能识别出这种结构,进一步压低存储空间。

正是这三个特征,让物联网数据成为数据压缩算法的理想用武之地。通用压缩算法虽然也能用,但针对时序特征的专用方案,往往能获得更高的压缩比。

2. 数据特征分析与算法选型思路

2.1 先搞清楚数据长什么样,再谈压缩

在选算法之前,我强烈建议你先做一件事:把设备上报的原始数据真实导出一批出来,逐字段分析它的类型、取值范围和变化规律。我看到很多项目一上来就套用某个压缩算法,结果效果不好,问题往往就出在没吃透数据特征。

以我那个环境监测项目为例,原始上报的数据结构大概是这样的:

  • 设备 ID:普通字符串,看起来像ESP32S3-0001ESP32S3-0002,特点是前缀完全相同,只有末尾几位在变。
  • 时间戳:Unix 毫秒级整数,单调递增,相邻两条之间基本固定相差 30000 毫秒。
  • 温度:浮点数,保留 1 位小数,取值范围在 -20 到 60 之间。
  • 湿度:浮点数,保留 1 位小数,取值范围在 0 到 100 之间。
  • 电池电压:浮点数,保留 2 位小数,取值范围在 3.2 到 4.2 之间。
  • 信号强度:整数,通常在 -100 到 -30 之间。

把这些字段列出来后,压缩思路就清晰了一半。比如设备 ID 明显有大量重复前缀,做字典编码就很合算;时间戳相邻差值稳定,做差分编码几乎能榨干冗余;温度和湿度是缓慢变化的小数,整体做一次缩放转成整数,再做差分,压缩效果会非常可观。

2.2 通用压缩算法与物联网场景的匹配度

接下来聊聊算法选型。很多工程师第一反应是用 gzip,毕竟它太普及了,随手就能调库。我自己也试过,gzip 对 JSON 文本的压缩率不错,能把 10KB 压到 1KB 左右,但它是通用算法,没有利用时序数据的任何结构特征。更重要的是,gzip 压缩时需要维护较大的字典窗口,对 CPU 和内存都有一定开销,在低功耗嵌入式设备上跑起来并不划算。

我整理过一张常用压缩算法跟物联网场景的匹配度对比,实际参考价值比较高:

算法压缩比压缩速度解压速度CPU 开销物联网适配性
gzip适合冷数据归档,不适合端侧实时压缩
LZ4极快极快适合网关或端侧,兼顾速度和压缩比
Snappy极快极快适合数据管道,Google 系协议常用
Zstandard性价比很高,可调压缩级别
delta+varint很高(时序专用)极快极快极低适合数值型时序数据,强烈推荐

从这张表能看出,通用算法追求的是对任意数据都能压,而物联网场景更多是压那些有规律的数字序列。因此在端侧或者网关位置,我更倾向于用轻量级方案,把“通用压缩”和“时序专用处理”结合起来,而不是直接上一个 gzip 了事。

2.3 时序数据专用压缩思路:delta 编码和 Gorilla 方案的启示

这个领域有一篇绕不开的论文,就是 Facebook 提出的 Gorilla 时序数据压缩算法,后来也演化成了我常用的思路。它的核心不在于发明什么惊天动地的数学原理,而是非常聪明地抓住了时序数据中“相邻数据变化极小”这个事实。

先说最简单的 delta 编码。对于时间戳序列,比如170000000000017000000300001700000060000,如果直接存原始值,每个要占 8 字节。但如果我们存的是差值,那就是3000030000,第一个数需要 8 字节,后面的每个只需要几个字节就够了。更进一步,Gorilla 提出来的 delta-of-delta:对差值再做一次差值,因为采样间隔固定,第二步计算出来的值基本是 0。存一串 0 的成本几乎可以忽略不计。

再比如温度值27.427.527.5,先把小数缩放成整数274275275,再做一个一阶差分,得到27410。后面这些小数用什么方式表示都行,关键是数据被极大地“规整”了,后续不管是继续做变长整数编码,还是进一步做霍夫曼编码,效果都会好很多。

这套思路本质上就是把“数据之间的相关性”显式地抽出来,而不是让压缩器自己从字节流里慢慢摸索规律。对物联网这种采样频率高、相邻数据波动小的场景,这是非常对路的方案。

3. 核心实现:一套开箱即用的压缩与存储方案

3.1 整体架构:端侧预处理 + 网关二次压缩 + 云端列式存储

在讲具体算法之前,先把整体链路定下来。我目前推荐并验证过的架构分三层:

第一层是端侧。在设备端拿到原始数据后,不直接发 JSON,而是先做一个轻量级的规整处理。包括丢弃冗余字段、将小数统一放大成整数、将时间戳转成相对偏移等。这层只做无损的变换,不做复杂的统计编码,因为设备端的计算资源有限。

第二层是边缘网关。设备数据发到网关后,由网关做二次压缩。网关的算力通常比设备强不少,可以运行 LZ4 或 Zstandard,甚至可以对一批数据做整体的差分和变长编码。多设备数据的聚合压缩,这层我认为是收益最大的地方,因为同一时间点附近的数据之间存在较大的横向相关性。

第三层是云端存储。收到网关上传的压缩数据后,云端负责解压、校验、入库。因为数据在传输前已经压过一遍,网络流量开销也同步降了下来。云端存储建议配合列式存储或时序数据库使用,这类系统本身对压缩友好,再叠加我们前两层的处理,效果可以拉满。

这三层说到底是一条流水线:规整、聚合、压缩、存储。每一层只做自己最擅长的事,避免让某一端承担过重任务。

3.2 端侧算法实现:差分编码 + 可变长整数编码

下面我用一个具体示例,演示端侧最常用的一套轻量压缩流程的实现。这里我用 Python 写伪代码,方便讲解思路,设备端建议用 C 或 Rust 实现同样的逻辑。

假设我们需要上报温度和湿度:

  • 原始数据:{"device":"ESP32S3-0001","ts":1700000000000,"temp":27.4,"hum":65.3}
  • 端侧变换前,先对数据排序并做一些规整:
# 伪代码:端侧数据规整与差分编码 def encode_batch(samples): # samples 是一个列表,每个元素是 (ts, temp, hum) # 第一步:把温度/湿度放大为整数,避免浮点存储 int_samples = [(ts, int(round(temp * 10)), int(round(hum * 10))) for ts, temp, hum in samples] # 第二步:对时间戳做一阶差分 ts_prev = int_samples[0][0] deltas = [ts_prev] # 第一个时间戳完整保留 temp_prev = int_samples[0][1] temp_deltas = [temp_prev] hum_prev = int_samples[0][2] hum_deltas = [hum_prev] for ts, temp, hum in int_samples[1:]: deltas.append(ts - ts_prev) ts_prev = ts temp_deltas.append(temp - temp_prev) temp_prev = temp hum_deltas.append(hum - hum_prev) hum_prev = hum return deltas, temp_deltas, hum_deltas

差分编码做好后,还需要把整数序列压缩成尽可能少的字节。常见的手段是可变长整数编码,也就是所谓的 varint。原理简单说就是:数值小的时候,用一个字节就能表示,而不是固定用 4 字节或 8 字节。

def varint_encode(value): # 将非负整数编码为变长字节序列 value = value & 0xFFFFFFFF out = bytearray() while True: b = value & 0x7F value >>= 7 if value: out.append(b | 0x80) else: out.append(b) break return bytes(out)

负数怎么处理?可以对原始值做一次 zigzag 变换,把负数映射成正数,比如-1 -> 11 -> 2-2 -> 3,这样所有数都能用 varint 统一编码。

实测下来,这套“差分 + varint”对温湿度这类缓慢变化的数据,平均每条记录能压到 2-4 字节。如果原始 JSON 一条要 100+ 字节,这已经是几十倍的差距。

3.3 计算参数与配置:采样间隔、量化精度怎么选

压缩效果好不好,很多时候在采集策略阶段就已经决定了。这里有几个参数我觉得可以重点把控:

  • 采样间隔:间隔越稳定,差分编码的收益越大。很多设备因为网络抖动导致上报时间忽长忽短,差分会变得没什么规律。建议端侧做好时间戳对齐,尽量按固定间隔采集,实在有漂移就在网关层做插值或对齐处理。
  • 量化精度:温度传感器标称精度可能是 0.1 摄氏度,那我们放大 10 倍就够了,没必要放大 100 倍。精度越高,差分的范围越大,反而压缩效果变差。这里要做一次“够用就好”的取舍。
  • 批处理大小:端侧如果攒一批数据再压缩上报,压缩效果会明显优于单条处理。比如一次打包 100 条记录做差分,首条记录占用的“固定成本”被摊薄了。当然批处理会增加延迟,具体看业务容忍度。
  • 字典替换:设备 ID 这类重复度高的字段,建议在网关层做一个简单的字典映射。我有个项目里,设备 ID 从字符串ESP32S3-0001(大概 12 字节)映射成 uint16 整数(2 字节),光这一项整库体积就降了约 8%。

这些参数不是拍脑袋定的,建议根据真实数据做一轮离线测试,看看不同配置下压缩比的差异,再上线调整。

4. 实测效果、成本收益与问题排查实录

4.1 压缩效果对比实测

为了说明这套方案的实际价值,我把我环境监测项目里的真实数据做了一轮对比实验。实验对象是同一个时段、同一批 10 万条设备记录,分别采用几种不同方式存储:

存储方式原始大小压缩后大小压缩比备注
原始 JSON 文本12,480 KB-1.00直接入库,最笨的做法
JSON + LZ412,480 KB1,340 KB约 9.3:1网关压缩,速度极快
规整后的二进制 + delta8,920 KB390 KB约 22.9:1端侧规整 + 差分
规整后 + delta + Zstandard8,920 KB210 KB约 42.5:1全链路叠加

需要说明的是,压缩比会受数据波动程度的影响:数据越稳定,压缩比越高;数据剧烈变化时,压缩比会相应下降。但即便在波动较大的工业场景,我用这套方案也至少能压到 10:1 以上。

从成本角度看,假设原始方案一年产生 100TB 的存储需求,按云厂商时序数据库每 GB 每月 0.2 元估算,一年存储费用约为 24 万元。如果把数据压到 1/10,存储费用直接降到 2.4 万元;再配合冷热分层,把超过 30 天的数据转存到对象存储,费用还能再省一截。这笔账不论对创业团队还是大厂项目,都不是小数。

4.2 常见问题速查表

在实际落地过程中,我整理了下面这一张高频问题表,基本都是踩过坑之后才总结出来的:

问题可能原因处理思路
压缩率突然从 20:1 掉到 4:1采样间隔不稳定,或数据里混入了异常值检查原始数据是否有大量缺失,补数逻辑是否引入了重复填值
端侧压缩导致上报延迟明显增加批处理窗口设得太大调小批处理条数,或改成按时间窗口触发压缩
解压后的数据跟原始值对不上浮点转整数时精度丢失放大倍数必须统一,解压侧用同样的倍数还原
CPU 占用过高在低功耗设备上跑 Zstandard/gzip端侧只做差分和 varint,把重压缩放到网关
设备 ID 字典越来越大新增设备数量过多,字典频繁重建设计好字典分片或按项目ID隔离,不要全局共用一个字典
查询变慢批量解压导致查询线程阻塞优先在写入侧压缩,查询时直接读列式存储,尽量不去运行时解压

4.3 排查思路与避坑技巧

最后分享几个我觉得特别值得注意的细节。

第一个是压缩必须和查询解耦。很多人把压缩做在查询侧,也就是存原始数据,等查询的时候再临时解压。这个做法在数据量不大时没毛病,但数据量超过几十 GB 之后,查询时的 CPU 开销和延迟会让人抓狂。我强烈建议把压缩做在写入侧,存进去的就是紧凑格式,查询侧直接读已压缩的列数据。像 TDengine、ClickHouse 这类系统本身就支持列级压缩,配合起来非常顺手。

第二个是不要盲目追求极致压缩比。压缩比高当然好,但如果为了压缩一个本来就只有 200 字节的小报文,而引入复杂的状态管理、字典同步、跨批次编码,一旦其中一个环节出错,整个数据链路都会变得脆弱。我看到过有项目为了压缩比把简单业务搞到难以维护,这是得不偿失的。一个务实的策略是:端侧做规整,网关做聚合压缩,冷数据再上高压缩比算法归档。把合适的算法放在合适的层,比单纯某一个地方压得狠要重要得多。

第三个是压缩方案要能回滚、能灰度。数据压缩一旦上线,存量数据和新数据的格式可能不一致。我在实践中会先在测试环境验证一轮,比对解压后的数据与原数据的一致性,再选择几个低风险设备灰度上线,确认无误后逐步放量。宁可上线慢一点,也不要出现解压后数据对不上的事故。

回到我自己经历的那个环境监测项目,上线这套压缩方案之后,存储占用从最高 800GB 降到了不到 80GB,查询从几秒降到了毫秒级,每月的存储账单也只剩下原来的一个零头。后面我又在另外两个项目里复用了这套思路,针对不同的业务场景做了少量参数调整,效果都很好。压缩这件事,本质上就是花一点计算资源,去换存储和带宽的成本。对物联网这种天生数据密集、设备分散、成本敏感的场景来说,这笔账怎么算都划算。如果你正被存储成本困扰,我建议别急着扩容或清库,先看看数据本身,把压缩这件事安排上。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/9 21:52:10

Hermes WebUI Docker部署教程:三步跑通,新手友好

Hermes WebUI Docker部署教程:三步跑通,新手友好 【免费下载链接】hermes-webui Hermes WebUI: The best way to use Hermes Agent from the web or from your phone! 项目地址: https://gitcode.com/GitHub_Trending/he/hermes-webui Hermes Web…

作者头像 李华
网站建设 2026/9/9 21:51:43

STM32数字时钟实战:内部RTC与数码管动态扫描全解析

简介:基于STM32的数字时钟设计工程包,面向嵌入式系统初学者及STM32编程爱好者,聚焦如何借助STM32实现计时、闹钟触发与LCD液晶显示等完整功能。工程以C源码、头文件、Keil工程配置及Proteus仿真文件为主要构成,共182个文件&#x…

作者头像 李华
网站建设 2026/9/9 21:51:27

数学建模论文提交前AI自查方案:六大维度26项细节全排查

2026年国赛备考的同学,论文写完之后先别急着交。这次我们来看一套数学建模论文提交前的AI自查方案:把论文、赛题、附件一起丢给大模型,再输入固定指令,让它按六大维度26项细节逐项排查,最后输出一张可以直接对照修改的…

作者头像 李华
网站建设 2026/9/9 21:49:49

C++实现谱减法音频去噪:从原理到可移植代码

简介:面向音频处理与降噪应用开发者,这套C项目提供了一份注释清晰的音频去噪实现,可对带噪语音进行降噪处理,适合语音识别、音频分析、音乐后期等场景的入门与二次开发。压缩包共17个文件,以C/C源码(3个.c、…

作者头像 李华
网站建设 2026/9/9 21:49:29

CHM转PDF全流程指南:解决乱码、目录丢失与工具选型

简介:CHM2PDF 是一款面向技术文档编写者、电子书阅读者和跨平台办公人群的实用转换工具,专门解决 CHM(编译 HTML 帮助文件)在非 Windows 系统上阅读不便、通用性弱的问题,可将 CHM 完整转换成保留章节结构、书签和超链…

作者头像 李华
网站建设 2026/9/9 21:48:29

一个2B小模型,怎么才能学会好好玩文字游戏

你有没有玩过Wordle?就是那个每天一个单词,你猜五个字母,系统告诉你哪个字母对了、哪个字母在但位置错了、哪个字母压根不在里面的游戏。这游戏简单到小学生都能上手,规则清清楚楚写在那儿。但如果让一个只有20亿参数的小AI模型来…

作者头像 李华