4. 压缩算法选型:gzip、lz4、zstd对比

聊到OTA升级,压缩算法是个绕不开的话题。说白了,我们就是在跟带宽和存储空间较劲。你想想看,一个完整的车机镜像动辄几个GB,直接传过去?那用户体验可就太糟糕了。

我个人习惯把压缩算法分成三类:老牌稳重型、极致速度型、均衡全能型。正好对应我们今天要聊的gzip、lz4和zstd。

4.1 三剑客的基本盘

先简单介绍一下这三位的背景。gzip是90年代的老将了,基于DEFLATE算法,压缩率不错,但速度嘛...嗯,有点跟不上时代了。lz4是2011年出来的,它的设计目标很明确——要快,快到极致。zstd则是Facebook在2015年开源的,算是后起之秀,在压缩率和速度之间找到了一个很好的平衡点。

我在项目中遇到过不少团队,上来就选gzip,理由是“大家都用”。但说实话,在车机OTA这个场景下,gzip很多时候并不是最优解。

算法 压缩率(越小越好) 压缩速度 解压速度 内存占用
gzip (level 6) 2.5x - 3.0x ~50 MB/s ~100 MB/s ~256 KB
lz4 (default) 1.7x - 2.0x ~500 MB/s ~1.5 GB/s ~16 KB
zstd (level 3) 2.8x - 3.2x ~300 MB/s ~500 MB/s ~1 MB

上面这个表格是我基于实际车机平台(ARM Cortex-A72 @ 1.8GHz)测试出来的数据。注意,不同平台差异很大,别直接套用。

4.2 压缩率与解压速度的博弈

这里有个关键点——OTA升级中,解压速度比压缩速度重要得多。为什么?因为压缩是在服务器端做的,一次压缩,千万次解压。而解压是在车机上进行的,直接影响到用户的等待时间。

我曾经在一个项目中,团队选了gzip最高压缩级别(level 9)。压缩率确实漂亮,从2.8GB压到了800MB。但解压的时候出问题了——车机解压花了整整4分钟。用户坐在车里等升级完成,那个体验...嗯,你懂的。

核心权衡点:

  • 如果网络带宽是瓶颈(比如3G/4G网络),选高压缩率算法
  • 如果车机算力是瓶颈(比如低端MCU),选快解压算法
  • 如果两者都要兼顾,zstd是当前最优解

4.3 实际场景选型建议

根据我这几年的实战经验,不同场景的选型建议如下:

场景一:全量升级,大文件传输

这种场景下,文件动辄几个GB。我建议用zstd,压缩级别设在3-5之间。既能拿到不错的压缩率(2.8x左右),解压速度也能控制在1分钟以内。

# 服务器端压缩
zstd -3 -o update.img.zst update.img

# 车机端解压
zstd -d update.img.zst -o update.img

场景二:差分升级,小补丁包

差分升级生成的补丁包通常只有几十到几百MB。这时候lz4是更好的选择。因为补丁包本身已经很小了,再追求压缩率意义不大,反而解压速度更重要。

# 服务器端压缩
lz4 -1 patch.bin patch.bin.lz4

# 车机端解压
lz4 -d patch.bin.lz4 patch.bin

我的小技巧:在车机上做解压时,尽量用流式解压,不要一次性加载整个文件到内存。车机内存本来就紧张,一次性加载几个GB的镜像?那其他应用就别想跑了。

场景三:多分区并行升级

现在很多车都支持多分区同时升级。这时候CPU资源是共享的。我建议用zstd的低级别(level 1-2),或者直接用lz4。因为并行解压时,每个线程分到的CPU时间片有限,算法太快反而会因为锁竞争导致整体性能下降。

4.4 避坑指南

我曾经踩过的坑:

  • 别在车机上用gzip最高级别解压。有一次我在项目里用了gzip -9,结果解压到一半车机OOM了。后来查原因,是gzip解压时需要额外的内存来维护字典。
  • 注意字节序问题。服务器通常是x86(小端),车机可能是ARM(也是小端),但有些老平台是大端。压缩包跨平台传输时,一定要确认字节序一致。
  • 压缩级别不是越高越好。zstd的level 19压缩率确实高,但压缩时间可能是level 3的100倍。服务器CPU也是要钱的。

4.5 性能测试方法论

最后分享一个我自己的测试方法。别只看官方benchmark,那都是在理想环境下跑的。你要在自己的目标平台上测,而且要用真实数据测。

# 在车机上测试解压性能
time zstd -d -o /dev/null update.img.zst
time lz4 -d -o /dev/null update.img.lz4
time gzip -d -c update.img.gz > /dev/null

注意,这里我把输出重定向到了/dev/null,避免写盘操作影响测试结果。如果你要测真实的升级时间,那还得加上写盘时间。

嗯,总结一下我的个人经验:新项目优先考虑zstd,它基本覆盖了90%的场景。如果对解压速度有极致要求(比如升级时间要求30秒以内),那就上lz4。至于gzip...除非你的服务器环境只支持gzip,否则我建议还是别用了。

下一章我们会聊到断点续传和校验机制,这两个东西在OTA升级中同样重要。到时候见。