文章目录
- 一、为什么通用压缩算法面对时序数据“力不从心”
- 表 1 通用压缩与时序专属压缩对比
- 二、差分压缩:把完整时间戳变成差值
- 三、增量压缩:处理现实世界的采样抖动
- 四、浮点压缩:只保存发生变化的比特位
- 五、时序数据库不是只选一种压缩,而是组合压缩链路
- 六、不同时序数据库的压缩设计取舍
- InfluxDB / Prometheus TSDB:适合静态时序场景
- Apache IoTDB:结合设备模型做分组压缩
- KaiwuDB:在 LSM‑Tree 基础上兼顾动态时序
- TDengine:压缩与自研分片模型深度绑定
- 七、真正拉开差距的,不只是算法本身
- 八、总结
上一篇我们聊了为什么绝大多数时序数据库都会选择 LSM‑Tree 作为底层存储引擎:它依靠内存缓冲加顺序落盘,扛住了物联网、车联网 7×24 小时海量数据写入,解决了“写得进”的问题。但紧接着,下一个现实难题就摆在面前:存不下。
传感器、电表、车载终端每秒源源不断输出测点,比如温度、电压、振动、转速。百万级设备持续采集几个月,原始时序数据就会迅速膨胀。如果原样存储,磁盘成本和 IO 开销都会变得很高。gzip、Snappy 这类通用压缩算法大家并不陌生,但它们并不是为时序数据设计的。时序数据要获得真正有效的压缩,通常需要先识别出时间单调、数值连续、浮点高位相似等规律,再做数学层面的预处理。
今天这篇文章,我们一次性把这些问题讲清楚:拆解差分压缩、增量压缩、浮点压缩的核心逻辑,对比通用压缩与时序专属压缩的差异,并看看不同时序数据库在压缩能力上的设计取舍。
一、为什么通用压缩算法面对时序数据“力不从心”
通用压缩的核心思路,是把数据当成字节流,寻找重复字符串,然后用字典或短编码替换重复片段。它很适合文本、日志、报文这类重复片段明显的数据。但时序测点数据有几个典型特征:
数据主体是时间戳、整型数值、浮点数值,而字节层面的长重复串并不多;
连续采样的数值往往是平滑变化的,而不是大块字符串重复;
时间戳本身单调递增,但原始时间戳占用空间很大。
因此,通用压缩往往抓不住时序数据最关键的规律——时间连续和数值渐变,只能在字节重复层面做压缩,压缩比提升的空间会比较有限。真正高效的时序压缩,是先通过数学变换去掉冗余,再交给通用压缩做二次压缩。
表 1 通用压缩与时序专属压缩对比
| 对比维度 | 通用压缩算法 | 时序专属压缩 |
|---|---|---|
| 压缩依据 | 字节重复、字典替换 | 时间单调、数值连续、浮点位相似 |
| 处理对象 | 任意二进制字节流 | 时间戳、整型、浮点测点 |
| 核心逻辑 | 统计重复字节片段 | 求差值、求增量、位裁剪 |
| 处理层级 | 直接压缩原始数据 | 先预处理,再二次压缩 |
| 优势场景 | 文本、日志、报文 | 传感器、物联网、工业时序 |
| 短板 | 难以识别数值连续关系 | 乱序、剧烈突变会降低收益 |
💡 小结论: 时序数据库并不是不用通用压缩,而是通常会先做时序预处理,再把结果交给 Snappy、ZSTD 这类通用压缩,形成更高的整体压缩比。
二、差分压缩:把完整时间戳变成差值
差分压缩主要针对时间戳和单调递增整型。一条原始时间戳可能占用 8 字节。如果百万条数据都存储完整时间戳,空间开销会非常大。但时序场景中,时间戳通常有一个重要特点:按采集顺序向前推进,前后差值很小。差分压缩的思想很简单:不保存每个时间戳的完整值,而是保存 “当前时间戳减去上一个时间戳” 的差值。
设第 i 条时间戳为t_i,则差分结果为:
d_i = t_i - t_(i-1)
实际存储时,通常只需要保存一个基准时间戳,再保存后续的差值序列。解码时,用基准值依次累加差值,就能还原全部时间戳。
举例来说:
原始时间戳:1000, 1100, 1200, 1300
差分后:基准 1000, 差值 100, 100, 100
如果采样严格等间隔,差值会大量重复,后续再配合字典压缩,压缩效果会非常明显。
不过,差分压缩也有边界。一旦出现乱序、补传或时间戳跳变,差值会忽大忽小,压缩收益就会下降。
三、增量压缩:处理现实世界的采样抖动
理想情况下,采样间隔固定,差分后会得到大量相同差值。但现实中,网络抖动、传感器休眠、系统调度都会让采样间隔出现轻微变化。这时,可以在一阶差分的基础上再做一次差分,也就是所谓的增量压缩或二阶差分。
一阶差分:d_i = t_i - t_(i-1)
二阶增量:Δ_i = d_i - d_(i-1)
它的目标不是压缩原始时间戳,而是压缩 “差值的变化”。举例来说:
原始时间戳:1000, 1102, 1201, 1303
一阶差分:102, 99, 102
二阶增量:-3, +3
可以看到,虽然一阶差值并不完全相同,但二阶增量的绝对值通常很小。在很多接近等间隔的场景中,二阶增量甚至会大量等于 0,从而可以用很少的比特存储。因此,增量压缩比一阶差分更适合处理真实工业现场中 “近似等间隔但不完全均匀” 的数据。
工程提示:IoTDB、KaiwuDB、InfluxDB 等产品都在不同形式上支持二阶增量或类似的时间戳压缩逻辑,差异主要体现在编码实现、比特打包和对乱序窗口的处理上。
四、浮点压缩:只保存发生变化的比特位
差分和增量压缩解决的主要是时间戳的存储问题,而浮点测点才是时序数据里最有压缩价值、也最有挑战的部分。温度、压力、电压这类数据经常在小范围内连续变化。例如:
25.134, 25.136, 25.135, 25.137
如果把它们看作 IEEE 754 浮点数,连续数值之间常常有大量高位比特完全相同。浮点压缩的核心,就是只保存发生变化的低位比特。Gorilla 类浮点压缩的基本思路是:
将当前浮点数与上一个浮点数按位对比;
找出高位相同前缀和低位变化部分;
如果相同前缀很长,就只编码变化部分;
如果数值突变导致差异很大,则保存完整浮点数。
例如:
上一个值:1011 0101 0011 1010
当前值:1011 0101 0100 0011
其中高位1011 0101完全相同,真正变化的是后面一部分低位。浮点压缩可以只记录变化部分,从而减少存储空间。这种方法对平滑变化的传感器数据特别有效。但如果测点频繁跳变,新旧值差异很大,压缩收益会明显回落。
三类算法针对的数据形态不同,适用场景也各有侧重,放到一起对比会更直观:
| 算法 | 核心原理 | 适合对象 | 最佳场景 | 收益下降场景 |
|---|---|---|---|---|
| 差分压缩 | 一阶差值 | 时间戳、单调整型 | 严格等间隔、纯追加数据 | 乱序、补传、历史修正 |
| 增量压缩 | 二阶差分 | 时间戳、近似等间隔序列 | 工业现场、轻微抖动采样 | 时间戳大幅跳变 |
| 浮点压缩 | 位异或、位裁剪 | 浮点测点 | 滑变化的传感器数据 | 频繁剧烈跳变 |
五、时序数据库不是只选一种压缩,而是组合压缩链路
实际工程中,时序数据库通常不会只使用单一压缩算法。更常见的链路是:
对时间戳做差分或二阶增量压缩;
对整型做差分压缩;
对浮点型做 Gorilla 类位裁剪压缩;
将预处理后的数据再交给 Snappy 或 ZSTD 做二次压缩;
最终写入底层存储文件。
这个链路里,前几步负责去除时序数据的数学冗余,最后一步负责压缩字节层面的剩余重复。不同产品的主要差异在于:当数据不再理想时,还能不能保住压缩比。
六、不同时序数据库的压缩设计取舍
InfluxDB / Prometheus TSDB:适合静态时序场景
InfluxDB 和 Prometheus TSDB 都完整吸收了 Gorilla 压缩体系。在纯追加、很少历史改写的监控和简单物联网场景中压缩表现很好。但如果出现大量乱序补传或历史数据更新,序列连续性会被破坏,压缩比可能明显下降。InfluxDB 后续版本通过限制乱序窗口等方式做了一定缓解,但本质上更适合相对规整的静态时序数据。
Apache IoTDB:结合设备模型做分组压缩
IoTDB 的特点是把压缩和设备树形模型结合起来,按设备、测点组织数据,再做差分和二阶增量压缩。对于设备数量大、测点数量多、序列相对连续的工业物联网场景,这种分组方式可以提升压缩收益。不过,如果跨设备写入非常混乱,或者历史修正很多,序列连续性同样会受到影响,压缩效率也会下降。
KaiwuDB:在 LSM‑Tree 基础上兼顾动态时序
KaiwuDB 同样实现了差分、二阶增量和 Gorilla 浮点压缩体系。它的不同之处在于,针对标准 LSM‑Tree 做了内核层面的适配,增加了乱序写入窗口和更新标记机制。这使得它在面对车联网、能源行业常见的补传、历史修正等动态时序场景时,不会因为少量乱序数据直接破坏整体压缩效率。此外,KaiwuDB 还把压缩能力和冷热分层结合起来。热数据使用较轻的压缩策略,保证查询性能;冷数据使用更高压缩档位,降低长期存储成本。
TDengine:压缩与自研分片模型深度绑定
TDengine 没有采用标准 LSM‑Tree,而是基于自研时序分片模型组织数据。它的压缩逻辑和分片强相关。分片内部数据有序时,差分和浮点压缩都能发挥作用;但如果乱序数据频繁进入特定分片,分片内部有序性被破坏,压缩收益也会受到影响。所以,TDengine 的压缩表现,高度依赖数据模型设计和分片策略是否贴合业务。
七、真正拉开差距的,不只是算法本身
很多人会误以为,时序数据库的压缩能力主要取决于是否实现了差分、增量或 Gorilla 算法。但实际上,这些算法本身属于公开的时序压缩理论,大多数主流产品都会支持。真正影响实际压缩比的,往往是下面几个工程问题:
数据写入是否有序;
乱序补传窗口是否可控;
历史更新是否会破坏序列连续性;
存储引擎是否为动态时序做了专门适配;
压缩策略是否和冷热分层结合。
换句话说,算法决定压缩上限,存储模型决定这个上限能不能在真实业务中落地。
八、总结
通用压缩主要按字节重复建立字典,很难利用时序数据的时间连续和数值渐变规律;
差分压缩把完整时间戳压缩成差值,适合单调递增序列;
增量压缩对差值再做差分,适合处理轻微采样抖动;
浮点压缩通过位对比和位裁剪,只保存浮点数中发生变化的部分;
主流时序数据库通常会组合使用时间戳压缩、测点压缩和通用压缩;
InfluxDB、Prometheus 更适合静态时序;IoTDB 更适合设备模型清晰的工业采集;TDengine 的压缩表现和分片设计关系很大;KaiwuDB 则更强调在动态时序场景下保持压缩效率。