用LLM定制压缩算法
使用 LLM 帮助为我们的温湿度时间序列数据制作了定制压缩算法,将其压缩了约 x53.6。
我们的移动客户端不断接收来自婴儿监视设备的温度和湿度读数,我们希望存储这些数据。设备每 5 分钟发送一次读数,我们需要将其以 7 天的分辨率存储,准备好按设备提供服务。
1、问题
我们正在为移动客户端服务 temperature 和 humidity 传感器数据。设备的插入速率很高,每秒数千次读数,但查询频率却很低。
当前的数据格式如下:
timestamp : `u32` 32位无符号整数,自纪元以来的秒数
device_id : `i8` 8位无符号整数,设备标识符
value : `i8` 8位无符号整数,温度或湿度读数
每个读数大约 5 字节(时间戳 4 字节,设备 ID 1 字节,数值 1 字节)。考虑到这种格式,存储 100 万个设备读数(7 天数据)大约需要 400MB。以目前的规模,这将是巨大的(~400GB for a 7-day retention)。
要求:
- Appendable in O(1):我们需要能够追加新的读数,而无需每次都解码整个序列。移动客户端会按设备 ID 和日期查询数据,并可能请求特定时间范围。
- 保留间隔:客户端将原始读数显示为随时间变化的图表,因此间隔必须被保留。我们使用
timestamp(自纪元以来的时间)来表示这一点。 - 处理数据缺口:由于网络问题或设备离线,某些读数可能会丢失。当发生这种情况时,我们不应跳过时间戳,而应保留间隔。
- 存储效率:我们希望优化存储,而不浪费空间来表示相同的值。
2、解决方案
2.1 最简单的方案:只存储时间戳和数值
我们可以只保留 timestamp、device_id 和 value,而省略 delta。这将把读数减少到大约 3 字节。
优点:
- 最简单的实现
- 最小的存储大小
- 不需要任何额外解码逻辑
缺点:
- 客户端无法轻松可视化变化
- 无法计算插入率
- 没有内置的间隙检测
2.2 更好的方案:RLE 运行长度编码
对于重复值,我们可以只存储第一个实例和计数。
timestamp : `u32`
device_id : `i8`
value : `i8`
count : `u8` 8位无符号整数,读数重复计数
优点:
- 仍然保留时间戳
- 存储开销仍然很小(仅额外的 1 字节用于计数)
- 客户端可以轻松检测缺失的读数
缺点:
- 仍然无法轻易可视化原始时间序列
- 需要客户端实现解包逻辑
2.3 最佳方案:Delta + Zstd 编码
对于重复值,我们存储第一个值和与下一个值之间的差值(delta),并使用 zstd 压缩差值。
timestamp : `u32`
device_id : `i8`
delta : `i8` 8位有符号整数,与前一读数的差值
value : `i8` 被跳过(delta = 0 时)
优点:
- 极小的差值(通常
±1或0,1 字节) - 客户端仍然可以可视化时间戳
- 空值可以表示"无变化"
- 比原始
5 bytes节省约 70-80% 空间
缺点:
- 需要客户端计算实际时间戳(base_ts + sum(deltas))
- 无法轻松检测间隙(如果值每 5 分钟保持不变,delta 将为 0)
- 需要特殊逻辑来正确解码(必须按顺序处理读数)
3、当前实现
3.1 PCO L4 压缩 (25.8x 压缩比)
该实现使用 PCO (预测编码优化) 算法,这是一种专为物联网时间序列设计的编码方案。
示例压缩结果:
| 方法 | 平均大小 | 压缩比 | 可追加? |
|---|---|---|---|
| 未压缩 | 3270B | 1.0x | 否 |
| PCO L4 | ~117B | 27.9x | 否 |
| TSZ (Gorilla) | ~140B | 23.5x | 否 |
| RLE Delta | ~146B | 22.5x | 是 |
主要特征:
- 在物联网工作负载下实现了良好的压缩比
- 保持完整的时间戳
- 支持缺失数据的间隙处理
- 适用于我们的数据特征(重复值)
缺点:
- 比简单的基于计数的解决方案慢
- 在没有硬件加速的情况下可能不够高效
3.2 运行长度编码 (变长)
这是最简单的改进,使用 1-3 字节运行长度来表示读数。
压缩结果:~61B,~18.6x 压缩比。
优点:
- 比 PCO L4 更容易实现
- 可以处理不同的数据大小
- 无需复杂的位累加器
缺点:
- 仍然无法直接可视化时间序列
- 客户端需要实现更多解码逻辑
3.3 变量长度编码 + 自适应运行长度
我们动态决定每个读数的运行长度(1、2 或 3 字节),根据数据模式。
改进:
- 最高的压缩效率
- 适应不同数据模式
- 可以处理不同的设备数量
4、性能基准
在 7 天的数据集(10,000 个设备读数)上进行测试:
| 方法 | 平均大小 | 压缩比 |
|---|---|---|
| 原始数据 | 3270B | 1.0x |
| PCO L4 | ~117B | 27.9x |
| 变长 | ~61B | 18.6x |
最佳方法:PCO L4
在我们的测试中,PCO L4 被证明是最适合的,因为它提供了最好的压缩比,同时保持我们要求的所有功能。
5、我们可以做更好吗?
是的,有几个方向可以探索:
增量更新:如果数据以小批或增量形式接收,而不是一次性加载 7 天,我们可以优化内存使用。
边缘计算:如果我们发送原始读数到边缘设备并让它进行初步压缩,然后再发送到服务器,可以节省带宽和计算资源。
采样策略:如果我们不需要每个读数,可以使用更高的采样率(例如,每分钟而不是每 5 分钟),同时仍然保持足够的数据来进行有用的分析。
混合编码:对于重复数据使用 Delta + Zstd,对于唯一序列使用运行长度编码。
下一步行动:
- 评估 增量更新:确定我们是否可以以更小的批接收数据。
- 原型边缘压缩:创建一个服务端来接收原始读数并进行初步压缩,然后再发送到主数据库。
- 测试混合方法:实现 Delta + Zstd 编码,并测量其实际压缩比。
- 客户端协调:更新移动客户端以支持解码方法,包括间隙检测和正确的数据可视化。
原文链接: Hand-Crafting Domain-Specific Compression with an LLM
汇智网翻译整理,转载请标明出处