我自己第一次真正认真用Zstd,是被线上日志归档逼的。那会儿服务器上一堆Nginx访问日志,单天上百GB,老办法是gzip压缩完扔冷存储,但压缩一次要等半小时,解压还原更是慢到让人怀疑人生。后来换了Zstd,同一个目录,压缩从半小时压到两三分钟,解压基本是秒级,体积还不比gzip差多少。从那次以后,我给所有备份、归档、传输链路上的压缩环节都换成了Zstd,期间踩了不少坑,也总结出一套比较顺手的用法。
这篇东西不打算写成人人都知道的命令手册,就按我自己在Linux、macOS、Windows三个平台上从零用起来的全过程来写。Zstd全名Zstandard,是Facebook开源的高性能压缩算法,核心卖点就是“压缩速度快、解压速度极快、压缩率可调可控”。不管你是做后端开发、运维,还是经常在Windows上倒腾大文件的普通用户,只要碰过“压缩”这件事,Zstd都值得放进工具箱。它适合处理日志、数据库导出、容器镜像、CI缓存,也适合本地跨平台传文件,尤其是解压那一下的体验,用过就回不去。
1. Zstd带来的改变,以及它和gzip等工具的本质区别
1.1 从一次归档踩坑说起,Zstd到底解决了什么问题
先讲我自己的场景。之前压缩日志一直用gzip,因为它普及率高,Linux上随手就有。但gzip的最大问题是压缩和解压速度都不够快,尤其当数据大到GB甚至TB级别的时候,CPU时间全耗在等压缩上。有一次我压缩一个12GB的数据库导出文件,用gzip -6跑了大半个小时,中间还因为连接断开重来了一次,心态直接炸了。
后来我换成Zstd,同样的12GB文件,默认级别直接压,用了大概三分之一的时间,压缩出来的体积还小一点。更让我意外的是解压速度,gzip解压这个文件要五六分钟,Zstd差不多一分钟内搞定。原因在于Zstd在算法设计上做了很多针对现代CPU的优化,它能在压缩时预测数据里的重复模式,并利用短窗口和长窗口结合的方式,把常规文本、日志、JSON这类数据压缩得又快又小。
对普通人来说,你不需要理解LZ77、Huffman、FSE这些底层术语,只要记住一个结论:在绝大多数场景下,Zstd的压缩率接近甚至超过gzip,但压缩和解压速度却能快好几倍。如果你压缩的是重复度很高的文本、日志、导出文件,这种差距会非常明显。如果是视频、图片、已压缩过的zip包,那基本压不动,这是所有通用压缩算法的通病,不怪Zstd。
1.2 和gzip、xz、7z的横向对比,为什么不是越老越稳
很多人一听Zstd是2016年才出来的新算法,第一反应是不敢用,怕兼容性不行。我刚开始也有这个顾虑,但实际对比之后,想法就变了。这里放一张我自己平时做选型时会看的对照表,数据顺序按直观感受排:
| 工具 | 压缩率 | 压缩速度 | 解压速度 | 是否适合主流备份场景 |
|---|---|---|---|---|
| gzip | 一般 | 中等 | 中等 | 传统可用,但效率偏低 |
| bzip2 | 略高于gzip | 慢 | 很慢 | 不推荐 |
| xz | 高 | 很慢 | 中等偏慢 | 适合追求极致体积的离线归档 |
| 7z | 高 | 较慢 | 中等 | 跨平台支持好,但命令行生态偏弱 |
| Zstd | 中高(级别可调) | 快 | 极快 | 非常合适,尤其是高频压缩和解压场景 |
这个表不是说不让你用xz,如果你归档的文件需要放到长期冷存储里,并且完全不在乎压缩和解压时等待的时间,那xz依然是体积最优解。但只要你需要反复压缩、解压,比如每天跑备份、每周清日志,Zstd的优势就体现出来了。
举个例子,我给一个1GB的文本日志文件做过简单测试。gzip -6压缩耗时约22秒,压缩后约180MB;Zstd -3压缩耗时约3秒,压缩后约190MB,体积多了5%左右;Zstd -9压缩耗时约10秒,压缩后约170MB,已经比gzip -6小了,速度还快了一倍。解压就更夸张,gzip解压耗时约8秒,Zstd解压只要1秒出头。这就是我敢在备份链路里全面替换gzip的原因:同样的活,Zstd干得更快,最后的压缩结果也不吃亏。
需要注意的是,Zstd的压缩级别很多,从1到22,默认是3。级别越高压缩率越高,但压缩速度越慢,同时消耗的内存也更大。很多人上来就喜欢用最高级别,这其实是误区,后面我会单独讲怎么选级别。
2. 环境准备:三个平台安装与命令行快速上手
2.1 Linux / macOS安装,两条命令搞定
在Linux上装Zstd基本没有难度,各个发行版的软件源里都有。Debian和Ubuntu用:
apt update && apt install -y zstdCentOS、Rocky、AlmaLinux这些红帽系用:
yum install -y zstd新版系统如果你习惯dnf,直接把yum换成dnf就行。Alpine这种轻量镜像更简单:
apk add zstdmacOS用户用Homebrew:
brew install zstd装完之后验证一下:
zstd --version如果能输出版本号,比如*** Zstandard CLI (64-bit) v1.5.5 ***,就说明环境没问题。这个步骤看着简单,但我在很多服务器上见过装完就忘的情况,真正要用的时候发现命令不存在,所以建议装完顺手验证一下,养成习惯。
这里多说一句,旧版Linux发行版自带的zstd版本可能比较老,比如CentOS 7默认没有zstd,需要先启用EPEL仓库。版本老一点不是不能用,但如果对方机器上用了新版Zstd的高压缩级别或长窗口模式,老版本解压时可能报“unsupported frame parameter”,所以我一般建议重要备份场景下,源端和目标端尽量都用较新的zstd版本。
2.2 Windows下安装,以及“Windows压缩工具怎么卸载”的误区
Windows用户看到“压缩工具”四个字,经常本能地想到系统自带的“压缩文件夹”功能,然后搜出“Windows压缩工具怎么卸载”这种问题。这里必须先说清楚一个关键点:Zstd和Windows自带的压缩文件夹完全两码事,两者互不干扰。
Windows自带的“压缩文件夹”是资源管理器里的一个shell扩展,主要用来处理zip文件,它是系统功能的一部分,不是独立软件,正常情况也没法单独卸载,更没必要卸。你装了Zstd之后,并不会抢它的文件关联,也不会改变zip格式的处理方式。Zstd是命令行工具,默认没有图形界面,双击.zst文件不会像WinRAR那样弹出窗口,这是正常的,不是安装失败。
Windows上安装Zstd最方便的方式是用包管理器。已安装Scoop的话,执行:
scoop install zstd用Chocolatey的话:
choco install zstd -y不想装包管理器也可以去GitHub的facebook/zstd仓库Release页面下载Windows版本压缩包,解压后把zstd.exe所在目录加到系统环境变量的Path里。加Path的步骤是:右键“此电脑”->属性->高级系统设置->环境变量->编辑Path->新增一个路径,然后把命令行窗口关掉重开。
这里有一个我在Windows上踩过的坑:下载的是别人编译的旧版zstd.exe,命令行里执行没问题,但解压一个由新版Zstd使用--long参数压缩的文件时报错,原因就是旧版不识别长窗口帧参数。所以Windows上尽量用官方Release或包管理器里的最新版本,不要图方便随便找个网盘版本。
2.3 第一个压缩和解压命令,30秒建立信心
安装好之后,先拿个小文件跑一遍完整流程。在命令行里进入一个临时目录,创建一个测试文件:
echo "hello zstd, this is a test" > test.txt zstd test.txt正常情况下,目录里会多出一个test.txt.zst,原来的test.txt还在。zstd默认不会删除源文件,这跟gzip的默认行为不同,gzip压缩完会把源文件删掉,Zstd保留了源文件,这个设计在对数据和安全感要求高的人看来更友好,但如果你脚本里默认认为压缩后源文件没了,就要注意区分。
解压命令:
zstd -d test.txt.zst-d表示decompress。解压完成后目录里会重新出现test.txt,或者你也可以用更直观的unzstd test.txt.zst,效果一样。zstd和unzstd是两个可执行文件,Windows版解压包里两个都有,底层是同一个程序的不同入口。
如果想压缩完直接删除源文件,加上--rm参数;如果不想保留压缩后的文件,用--rm配合解压也可以。日常操作里我会在备份场景加上--rm,因为磁盘空间本来就紧张。但测试阶段建议先不加,等确认流程没问题之后再上。
3. 压缩级别和关键参数,怎么选才是最优解
3.1 压缩级别1到22,不是越高越聪明
Zstd最让人困惑的就是压缩级别,从1到22,选项多到像在逼你选择困难症发作。我见过不少同事第一次用Zstd,直接来了一句“那就最高级别吧”,然后跑了半天没压完,回头还嫌Zstd慢。其实级别选择这个东西,完全取决于你的场景,不存在一个万能答案。
简单分类一下:
- 级别1到3:压缩速度极快,内存占用低,适合日常处理、临时传输、日志压缩。默认级别3是绝大多数情况下的最优起点。
- 级别4到9:压缩率逐步提升,速度仍然比gzip快一到两个量级,适合备份、打包、需要长期保存的文件。
- 级别10到15:压缩率明显更好,但压缩时间开始拉长,适合离线归档、冷存储场景。
- 级别16到19:接近xz的压缩率,耗时已经比较夸张,适合一次性压缩、之后很少解压的文件。
- 级别20到22:必须配合
--ultra参数才能使用,压缩过程中内存占用极高,如果不是为了冲击极限压缩率,个人不建议在生产环境里用。
我自己常用的搭配是:即时压缩选zstd -3,备份归档选zstd -9,离线冷数据选zstd -15。19以上的级别我几乎只用过一次,那个压缩比确实香,但压一个10GB文件花了一个多小时,过程中CPU和内存都在狂飙,普通机器不一定扛得住。
如果你想知道当前数据在不同级别下的表现,可以用Zstd自带的基准测试命令:
zstd -b test.log这条命令会把默认几个级别跑一遍,输出每个级别的压缩率、压缩速度和解压速度。想指定级别,用-b3 -b9这种写法。不过注意,基准测试会读取目标文件多次,文件特别大的时候也会花不少时间,适合抽样做压测,不适合天天跑。
3.2 影响结果的不止级别,还有这些关键参数
除了级别,还有几个参数在实际使用中经常碰到,用好了可以解决很多具体问题。
第一个是--ultra。上面提过,级别20到22必须显式加--ultra,它允许Zstd使用超过常规限制的压缩参数。代价就是极大的内存开销和漫长的压缩时间。我的建议是,永远不要在业务服务器上用,除非你确认这台机器除了压缩没别的事可干。
第二个是--long=windowLog。这个参数应对的是“大文件里存在长距离重复”的场景。比如几十GB的日志文件,同一个堆栈信息可能隔了很远才会再次出现,默认的窗口大小抓不到这种重复,压缩率就会下降。加上--long=27之类的参数后,Zstd可以跨更大的窗口找重复,压缩率会有明显提升。代价是内存占用上升,而且解压端也必须支持--long,否则解不开。所以它更适合归档场景,不适合拿给外部合作方解压的文件。
第三个是-T多线程。Zstd默认单线程压缩,但对于大文件,多线程能明显缩短压缩时间。用法是:
zstd -T0 -9 archive.tar-T0表示使用所有CPU核心。我自己的备份脚本里基本都会加-T0,因为备份窗口越短越好。但要注意,多线程模式会占满CPU,对正在对外提供服务的机器影响很大,建议在凌晨低峰期跑,或者用-T4限制一下线程数。
第四个是--rsyncable。这个参数对增量备份很有用,它会让压缩数据每隔一段距离产生一个同步点,这样rsync同步时不需要因为中间几KB变化就重传整个压缩包。代价是压缩率下降约1%左右,换来的增量传输效率提升却非常明显,日志类文件的远程备份场景强烈推荐。
3.3 字典压缩,小文件批量场景的隐藏大招
Zstd有一个其他通用压缩工具很少见的功能:字典压缩。简单理解就是先从一个样本集合里训练出一个“字典文件”,压缩时带上这个字典,对于大量结构相似的小文件,比如一堆JSON日志、一堆配置文件,压缩率可以大幅提升。
训练字典的命令很简单:
zstd --train /path/to/samples/*.log -o mydict会生成一个命名为mydict的字典文件,然后压缩时用-D参数指定:
zstd -D mydict -3 app-2024.log解压时也需要用同一个字典:
zstd -D mydict -d app-2024.log.zst这个功能我从去年开始用于容器日志的集中归档,效果非常惊人,一堆几乎相同结构的文本日志,常规压缩只能压到65%左右,带字典后能压到15%以下。不过字典训练有几个注意点:样本必须和目标文件有相似结构,样本数量越多越好,至少几百个;字典文件本身要妥善保存,丢了字典,带字典压缩的文件就废了。所以我对字典文件的备份比数据文件还上心,直接扔进对象存储加版本管理。
4. 实战场景:备份、日志、传输与Windows使用的一次梳理
4.1 数据库和目录备份,管道压缩一学就会
数据库导出的SQL文件是压缩需求大户。以前我的习惯是先mysqldump导出来,再单独压缩,中间多了一次磁盘IO,还容易因为磁盘空间不够直接失败。用Zstd后我改成管道直连,一条命令完成:
mysqldump -u root -p mydb | zstd -3 -o mydb.sql.zst这样数据库导出的数据直接进入Zstd压缩流程,不落临时SQL文件,省时间也省磁盘。恢复的时候更简单:
zstd -dc mydb.sql.zst | mysql -u root -p mydb-d是解压,-c是输出到标准输出,合起来-dc就是解压后直接输出给管道。这个写法在很多备份脚本里都通用,建议背下来。
目录备份用Zstd时要注意一点:Zstd本身是单文件压缩工具,不处理目录结构。想压缩整个目录,得先交给tar打包。tar新版本原生支持Zstd,直接写:
tar --zstd -cf backup.tar.zst /data如果tar版本太老不支持--zstd,可以手动组合中间文件,或者用管道:
tar -cf - /data | zstd -9 -T0 -o backup.tar.zst注意管道写法里-o后面指定的是输出文件,同时因为是从标准输入读数据,不能再把-当成输入文件传给zstd。目标端的环境如果没有zstd,可以用tar --zstd -xf backup.tar.zst来解包,或者zstd -dc backup.tar.zst | tar -xf -。我习惯在备份脚本里用后面这个管道写法,因为它的兼容性更好,老版本tar也不区分。
4.2 日志轮转和长期归档,把logrotate调教好
日志轮转是Zstd最能发光发热的场景之一。原来logrotate默认用gzip,我总嫌它压缩慢,后来发现logrotate的配置文件里可以指定外部压缩命令,直接换成zstd。
拿Nginx日志举例,配置写在/etc/logrotate.d/nginx里,大致这样:
/var/log/nginx/*.log { daily rotate 30 compress compresscmd /usr/bin/zstd compressoptions -3 --rm compressext .zst missingok notifempty sharedscripts postrotate /usr/sbin/nginx -s reopen endscript }关键就三行:compresscmd指定zstd路径,compressoptions传参数,compressext把压缩后的扩展名改成.zst。我用--rm是因为日志轮转后源文件本来就会被安排处理掉,让zstd直接删源文件可以少一次文件操作。这样跑一段时间后,日志目录里就是一堆.zst文件,想看旧日志时执行:
zstd -dc 2024-12-01.access.log.zst | grep "关键字"解压速度极快,基本能做到“边解压边grep”,体验比gzip高出一个层次。
4.3 CI缓存和容器镜像,提速效果立竿见影
Zstd在GitHub Actions里的体现非常明显。Actions的缓存机制在较新版本里已经用上了Zstd,压缩和恢复缓存的速度比之前快很多。如果你在自建的CI系统里对缓存做过压缩,同样可以指定zstd -3,构建机的缓存恢复时间能缩短一大截。我维护的几个项目,构建缓存从1GB左右压到200MB,恢复时间从半分钟降到十秒左右,整个流水线体感流畅很多。
容器镜像层压缩是另一个成熟的应用。Docker构建时,BuildKit支持将镜像层压缩格式设成Zstd,配置环境变量:
export BUILDKIT_COMPRESSION=zstd或在BuildKit的配置里指定compression = "zstd"。镜像层用Zstd压缩后,构建和推送速度都更快,拉取解压也更快。这里唯一的坑是兼容性:老版本Docker守护进程不一定支持Zstd压缩的镜像层,推到仓库之后,如果拉取端版本太老可能拉不下来。所以在团队内部要统一Docker版本,或者至少在公共镜像上保留gzip兼容层,这是我踩过坑之后学到的教训。
4.4 Windows用户怎么处理GUI和文件关联问题
回到Windows这个相对“非主流”的使用场景。Zstd的命令行方式在Windows的PowerShell和CMD里都能用,和Linux语法完全一致。如果你实在不习惯命令行,可以装PeaZip这类支持Zstd的图形压缩软件,界面操作,右键就能压缩解压。但需要明确一点,PeaZip只是把Zstd封装成了图形界面,底层的.zst文件仍然是通用的,用命令行照样能解。
关于Windows自带压缩工具的问题,我再解释得明白一点:系统自带的“压缩文件夹”不需要卸载,也尽量不要去卸载或禁用。它平时不占CPU、不占内存,只有在右键压缩解压zip时才会被调用。真正让Windows变卡的往往是各种第三方压缩软件的开机自启和后台驻留,如果你装了WinRAR、好压、360压缩这类工具觉得烦,直接卸载它们就好,完全不影响Zstd的使用。卸载之后Zstd命令照常运行,它依赖的是命令行环境,和GUI压缩软件没有任何关系。
有一种常见误解是,装了Zstd之后为什么双击.zst文件没反应,是不是和系统压缩工具冲突了。其实不是。Zstd官方在Windows上主打命令行,没有默认的文件关联。想让.zst后缀和图形界面关联,需要借助PeaZip这类工具,或者在PeaZip里把.zst关联上。如果不想关联,每次右键选择“打开方式”指定一下也凑合。
5. 高频问题与避坑笔记,照着排查基本能救回来
5.1 解压报错Unrecognized file format,先别急着删文件
刚上手时最慌的错误就是解压时报Unrecognized file format。这个错误的意思是zstd识别不了目标文件的格式。常见原因有几种:文件确实不是Zstd压缩的,比如文件名被改成了.zst但内容还是gzip;文件下载不完整,头部数据损坏;文件本身加密过,或者套了一层别的格式。
我的排查顺序是:先用file命令看看文件真实类型:
file suspicious.zst如果输出显示gzip compressed data,那就用gzip -dc解压。如果显示data或者ASCII text,那可能文件就没压缩过,直接忽略扩展名读取即可。如果显示Zstandard compressed data但zstd仍然报错,那就是文件头部或中间内容损坏了,这种情况只能用备份恢复,或者用zstd -t做一次更详细的完整校验,看错误的精确位置。
5.2 压缩率达不到预期,可能不是Zstd的问题
有次一个同事跑完备份,发现SQL文件只压了30%,跑来问我怎么Zstd这么弱。我看了一下他的原始文件,发现是去年已经用xz压过一遍的备份,问他为什么把已压缩文件再压一遍,他说为了统一归档格式。这就是典型的压缩率误区。任何通用压缩算法都只能压缩数据里的冗余,已压缩过的数据冗余度极低,再压一次基本白费力气,还白白消耗CPU。
如果你的数据确实是未压缩的文本,但Zstd默认级别压出来体积不理想,可以从两个方向调整:一是把级别调到9到15,压缩率会继续提升;二是对特别大的文件试试--long参数,让Zstd能在更大范围内发现重复模式。我压过一个几十GB的日志文件,没用--long时压缩率大约是16%,加上--long=27后直接降到12%,差距还是挺明显的。
5.3 磁盘和内存告急,级别和窗口如何妥协
压缩大文件时,最容易忽略的是内存问题。Zstd的解压端内存需求取决于压缩时使用的窗口大小,默认一般是8MB,几乎可以忽略。但如果压缩时用了--long=30这类大窗口,解压端也需要分配对应的大块内存,在内存只有2GB的小机器上就可能卡死或OOM。
推荐的做法是:压缩端如果明确知道目标机器内存很小,就不要用超过27的窗口;如果需要超大窗口的高压缩率,还要在归档说明里写清楚必须用哪个版本的zstd。我的一个无线下小服务器就吃过这个亏,解压一个用--ultra -22压缩的归档文件时,内存瞬间吃满,最后只能拿到高配机器上解压。
磁盘方面,Zstd压缩和解压过程本身不产生额外临时文件,不像某些工具需要临时空间存放中间结果。但管道压缩要注意输出文件和源文件不能放同一个分区且该分区剩余空间不足,否则压缩到一半就把盘写满了。我的习惯是压缩前先检查目标分区剩余空间,估算压缩包大小,至少留出压缩前体积20%的余量。
5.4 Windows场景的卸载、关联和误删问题
很多Windows用户搜“压缩工具怎么卸载”,其实想解决的是“我想换一个新的压缩工具”。如果你装了Zstd后觉得不好用,卸载也很简单。包管理器安装的就用对应命令删除:
scoop uninstall zstdchoco uninstall zstd手动解压的版本更简单,把整个文件夹删掉,再把之前在Path里加的路径删掉就行,不写注册表,不留垃圾文件。Zstd对系统是“绿色软件”级别的存在,这一点比很多权限混乱的国产压缩软件干净得多,也是我推荐它的一部分原因。
最后提醒一个容易手滑的地方:删除.zst文件前一定确认解压过。我在Windows上就有过一次惨痛经历,把压缩包传给客户后本地原文件删了,后来发现那个压缩包因为用了带字典参数生成的文件,字典没一起发过去,客户解不开,自己又没留份,只能重新从源数据压一遍。从那以后,所有带字典的压缩文件我都会在归档目录里同时保存一份字典副本,并命名成:zstd-dict这样的固定后缀,防止混在一起找不到。
5.5 命令行找不到zstd,多半是Path问题
最后聊一个特别基础但很多人问的问题:明明安装了Zstd,但输入zstd提示command not found或者“不是内部或外部命令”。Linux和macOS上,一般是安装的bin目录不在当前用户的PATH里,用which zstd看一下真实的执行路径,如果输出为空,考虑重装或者找到安装路径后手动加入PATH。
Windows上更常见的是解压了官方包但没配置环境变量。这里有个小技巧:不需要非得开“系统属性”去改Path,在PowerShell里临时用绝对路径调用也是一种方式:
D:\tools\zstd\zstd.exe --version如果你经常要用,再把D:\tools\zstd加到用户Path里。加完PATH之后一定要重开终端,否则当前会话不会生效,这个细节能挡住一半的新手。
我自己的个人体验是,Zstd用顺了之后,回到gzip就回不去了,解压速度和压缩速度的优势实在太明显。如果你正好在纠结备份脚本、日志轮转、大文件传输这些场景,拿个小文件先试一把Zstd,应该能很快感受到区别。最后再分享一个小技巧:所有用到管道压缩的地方,无论是tar、mysqldump还是rsync,都值得先跑一遍小数据量测试再上生产,因为不同版本的Zstd在某些参数组合下的表现差异还是存在的,提前测一遍能省掉很多麻烦。