4. 常见压缩算法详解

在 OTA 镜像压缩工程中,算法选型直接决定了三件事:镜像包体积、端侧解压耗时、以及服务端压缩吞吐。很多团队只盯着“压缩率”一个指标,结果在低端车机或 IoT 设备上出现解压卡顿、CPU 飙高、升级窗口超时。本节把 DEFLATE、LZ4、Zstandard、Brotli、Gzip 放在同一张“压缩率—速度—内存”坐标系里讲清楚,帮助你在不同镜像类型和硬件档位上做出可落地的选择。

一、核心原理:五类算法其实分属两条技术路线

这五种算法并不是并列关系,而是“字典压缩 + 熵编码”组合方式不同。理解它们的家族关系,比死记参数更重要。

  • LZ4:纯 LZ77 系字典压缩,只做“匹配—复制”,几乎不做熵编码。它的设计目标是极致解压速度,压缩率通常最低,但解压可达 GB/s 级。
  • DEFLATE:LZ77 字典 + 霍夫曼熵编码,是 Gzip、ZIP、PNG 的底层算法。压缩率中等,解压速度中等,兼容性最好。
  • Gzip:严格说是“DEFLATE + gzip 容器头/尾(CRC32、ISIZE)”,算法内核就是 DEFLATE,因此压缩率与 DEFLATE 基本一致,只是多了封装开销。
  • Zstandard(Zstd):LZ77 系 + 有限状态熵(FSE)/霍夫曼,支持 1~22 级压缩,且提供“字典训练”能力。它在压缩率与速度之间提供了连续可调的曲线。
  • Brotli:LZ77 变体 + 上下文建模 + 静态字典(内置常见 Web/文本片段),压缩率最高,但压缩慢、解压内存占用偏高,适合静态资源而非高频小包。
关键结论:LZ4 与 Brotli 位于“速度—压缩率”光谱的两端,DEFLATE/Gzip 居中偏保守,Zstd 是唯一能通过级别调节覆盖大部分场景的“全能型”算法。

二、算法性能对比:一张表看清选型边界

下表以典型 OTA 镜像(混合二进制 + 资源文件,约 500MB)为参考,数值为工程经验区间,实际会随数据熵和硬件变化。

算法 压缩率(相对原始) 压缩速度 解压速度 解压内存 典型适用场景
LZ4 约 50%~60% 极快 极快(GB/s 级) 极低 端侧实时解压、低端设备、差分补丁
DEFLATE 约 30%~40% 中等 中等 低 兼容性优先、ZIP/PNG 生态
Gzip 约 30%~40% 中等 中等 低 HTTP 传输、日志归档、通用分发
Zstandard 约 25%~35%(可调) 快~中等(级别可调) 快 中低 OTA 主镜像、需平衡体积与耗时
Brotli 约 20%~30% 慢 中等偏慢 中高 静态资源、Web 包、一次性下载

从表中可以看出:如果端侧 CPU 弱、升级窗口紧,LZ4 是安全牌;如果带宽是瓶颈、端侧算力充足,Brotli 或高等级 Zstd 更划算;Gzip 则是“哪里都能用,但哪里都不极致”的兜底方案。

三、方法流程:OTA 镜像压缩的推荐流水线

实际工程中很少只用一种算法,而是按“镜像分层 + 算法分级”组合。下面是一条经过验证的流水线:

  1. 镜像分层:将系统镜像拆分为 boot、system、vendor、资源包等独立块,便于差异化压缩。
  2. 熵评估:对每层计算熵值,已压缩数据(如 JPEG、APK)不再二次压缩,避免负收益。
  3. 算法匹配:高熵块用 LZ4 或 store,低熵文本/代码块用 Zstd 高等级或 Brotli。
  4. 字典训练:对 Zstd 使用历史镜像样本训练字典,小文件压缩率可提升 10%~20%。
  5. 并行压缩:Zstd 支持多线程,服务端按核数并行,缩短打包时间。
  6. 校验与回滚:压缩后写入 CRC32/SHA256,端侧解压失败可回退到原始分区。
# Zstd 多线程压缩示例(服务端打包)
zstd -T8 -19 --long=27 -o system.img.zst system.img

# LZ4 高速压缩(端侧友好)
lz4 -9 -B4 --content-size system.img system.img.lz4

# Gzip 兼容模式
gzip -9 -k system.img

# 解压耗时对比(端侧实测脚本片段)
time zstd -d system.img.zst -o /dev/block/by-name/system
time lz4 -d system.img.lz4 -o /dev/block/by-name/system

四、案例与场景:不同硬件档位的选型实践

场景 A:低端车机(4 核 A53,2GB RAM)。升级包 800MB,要求 3 分钟内完成。实测 Brotli 解压耗时超过 90 秒且内存峰值高,Zstd-19 解压约 35 秒,LZ4 仅 12 秒但包体增大到 480MB。最终采用“Zstd-9 + LZ4 混合”:核心分区 Zstd,资源分区 LZ4,整体升级时间控制在 70 秒内。

场景 B:云端 OTA 分发(带宽敏感)。镜像以文本配置和脚本为主,Brotli 将包体从 320MB 压到 78MB,虽然服务端压缩耗时增加,但 CDN 流量成本下降约 60%,端侧为高性能网关,解压耗时可接受。

场景 C:差分升级补丁。补丁本身很小(几 MB),但数量多、频次高。使用 Zstd 字典训练后,平均补丁体积再降 15%,且解压速度满足秒级安装。

经验法则:先看端侧解压预算(CPU 时间 + 内存),再看带宽成本,最后才看压缩率。顺序反了,很容易做出“包最小但装不上”的方案。

五、误区与复盘:三个常见踩坑点

  • 误区一:压缩率越高越好。 Brotli-11 压缩率确实最低,但服务端压缩可能耗时数十分钟,且端侧解压内存翻倍,低端设备直接 OOM。
  • 误区二:所有数据都值得压缩。 已压缩的 JPEG、MP4、APK 再压缩往往体积不变甚至变大,应先做熵检测,高熵块直接 store。
  • 误区三:忽略解压内存。 Zstd 高等级和 Brotli 的解压窗口较大,在内存受限的 MCU 或低端 SoC 上必须实测峰值内存,而不是只看压缩率。
复盘建议:建立“算法—硬件—镜像类型”三维选型矩阵,每次 OTA 发布前用真实设备跑一遍解压耗时与内存峰值,把数据沉淀为团队基线,避免每次凭感觉选算法。
压缩率 — 解压速度 定位图 越靠右上:压缩率越高且解压越快;越靠左下:速度优先、体积偏大 压缩率(相对原始体积,越右越小) 解压速度(越上越快) LZ4 极速解压 · 体积偏大 Gzip DEFLATE 内核 · 兼容性好 Zstd 级别可调 · 字典训练 Brotli 压缩率最高 · 解压偏慢 端侧低算力优选区 带宽敏感优选区 速度优先 均衡兼容 可调全能 压缩率优先

总结来看,OTA 镜像压缩没有“最好”的算法,只有“最匹配当前硬件与网络约束”的组合。把 LZ4 当作速度底线,把 Zstd 当作主力可调引擎,把 Brotli 留给带宽敏感且端侧算力充足的场景,把 Gzip/DEFLATE 作为兼容兜底,就能在体积、耗时与稳定性之间取得可控的平衡。