rclone Compress 压缩后端实战指南:为任意云端远程叠加 gzip/zstd 透明压缩
导读
Compress 是 rclone 中一个以"包装(wrap)"方式工作的远程(remote)类型:它把另一个已配置的远程作为底层存储,在上传时对文件进行 gzip 或 Zstandard(zstd)压缩,读取时自动解压,从而让任何云存储远程都具备透明的按文件压缩能力。本文以官方文档 docs/content/compress.md 为主体,结合 backend/compress 的源码实现,讲解它的适用场景、交互式配置、两类压缩算法与压缩级别选择、底层的存储文件布局与命名规则,以及每个配置项的作用和源码级工作机理。读完本文,你将能独立创建一个 Compress 远程,并根据文件类型合理选择算法、级别与缓存参数。
该功能自 rclone v1.54 引入,目前仍处于 实验性(experimental) 阶段。
什么是 Compress 远程:透明压缩而非归档
Compress 的核心思路并不是把多个文件打包成一个压缩归档,而是对单个文件逐个压缩后上传。正如官方文档所述,它最适合"包含大量可压缩大文件"的远程场景——典型如文本日志、CSV 数据导出、JSON 备份等。
从其源码注册信息看(backend/compress/compress.go#L76-L82),它的类型名为 compress,描述为 "Compress a remote",其 Fs 结构体内嵌了一个被包装的底层 fs.Fs:
// Fs represents a wrapped fs.Fs
type Fs struct {
fs.Fs
wrapper fs.Fs
...
}
也就是说,所有读写请求最终都会被转发给 remote 选项中指定的那个底层远程。用户日常使用 rclone 时,只需要把路径前缀写成 compress:,后续的 copy、sync、mount、serve 等命令一律照常工作,压缩与解压对操作者透明。
实验性状态警告
在投入生产使用前,请务必正视官方给出的实验性声明:
- 该远程目前处于 experimental 状态,可能出现故障或数据丢失;
- 使用者的任何操作都自行承担风险;
- 请勿在关键应用中依赖此远程。
这意味着在正式环境大规模使用前,应先在小范围、可重建的数据集上充分验证,并保留原始数据备份。
交互式创建 Compress 远程
创建方式与普通远程无异——运行 rclone config,选择类型 compress,然后回答两个必填问题(目标远程、压缩方式)即可。官方文档给出的完整交互流程如下:
$ rclone config
Current remotes:
Name Type
==== ====
remote_to_press sometype
e) Edit existing remote
n) New remote
d) Delete remote
r) Rename remote
c) Copy remote
s) Set configuration password
q) Quit config
e/n/d/r/c/s/q> n
name> compress
Option Storage.
Type of storage to configure.
Choose a number from below, or type in your own value.
...
12 / Compress a remote
\ (compress)
...
Storage> compress
Option remote.
Remote to compress.
Enter a value.
remote> remote_to_press:subdir
Option mode.
Compression mode.
Choose a number from below, or type in your own value of type string.
Press Enter for the default (gzip).
1 / Standard gzip compression with fastest parameters.
\ (gzip)
2 / Zstandard compression — fast modern algorithm offering adjustable speed-to-compression tradeoffs.
\ (zstd)
mode> gzip
Option level.
GZIP (levels -2 to 9):
- -2 — Huffman encoding only. Only use if you know what you're doing.
- -1 (default) — recommended; equivalent to level 5.
- 0 — turns off compression.
- 1–9 — increase compression at the cost of speed. Going past 6 generally offers very little return.
ZSTD (levels 0 to 4):
- 0 — turns off compression entirely.
- 1 — fastest compression with the lowest ratio.
- 2 (default) — good balance of speed and compression.
- 3 — better compression, but uses about 2–3x more CPU than the default.
- 4 — best possible compression ratio (highest CPU cost).
Notes:
- Choose GZIP for wide compatibility; ZSTD for better speed/ratio tradeoffs.
- Negative gzip levels: -2 = Huffman-only, -1 = default (≈ level 5).
Enter a value.
level> -1
Edit advanced config?
y) Yes
n) No (default)
y/n> n
Configuration complete.
Options:
- type: compress
- remote: remote_to_press:subdir
- mode: gzip
- level: -1
Keep this "compress" remote?
y) Yes this is OK (default)
e) Edit this remote
d) Delete this remote
y/e/d> y
上面示例中的配置要点可以拆解如下:
- remote:填写一个已经存在的远程,可以带上子目录前缀(如
remote_to_press:subdir),最终所有压缩文件都会写入该前缀下; - mode:gzip(默认)或 zstd;
- level:与所选 mode 匹配的压缩级别,回车使用当前 mode 的默认值。
防止自我引用
源码在 NewFs 中会做一项安全校验(backend/compress/compress.go#L197-L200):
remote := opt.Remote
if strings.HasPrefix(remote, name+":") {
return nil, errors.New("can't point press remote at itself - check the value of the remote setting")
}
即如果 remote 选项指向了 compress 远程自身(remote 前缀等于当前远程名加冒号),会直接报错 "can't point press remote at itself",避免形成无限嵌套的包装。
压缩算法与级别选择
GZIP:广泛兼容的经典选择
GZIP 是历史悠久、部署最广的压缩算法,在压缩速度与压缩比之间取得均衡。它支持的级别区间为 -2 到 9,其默认值含义与常见的 zlib/gzip 有所不同:
| GZIP 级别 | 含义 |
|---|---|
-2 |
仅 Huffman 编码,不进行 LZ 匹配,除非清楚自己在做什么否则不建议使用 |
-1(默认) |
官方推荐,约等价于常规 level 5,是大多数场景下的有效折中 |
0 |
关闭压缩(仅封装) |
1–9 |
级别越高压缩率越高、速度越慢;超过 6 后收益通常很小 |
源码中 GZIP 走的是 gzipModeHandler(backend/compress/gzip_handler.go),其压缩器基于 github.com/buengese/sgzip 提供的可随机读取的 gzip 实现:
gz, err := sgzip.NewWriterLevel(pipeWriter, f.opt.CompressionLevel)
sgzip 属于"可 seek 的 gzip"实现,它在标准 gzip 流上附加了块索引元数据,这正是 Compress 远程能对压缩文件进行随机读取(按 offset/range 读取)的基础。
Zstandard(zstd):现代高性能选择
zstd 是 Facebook 开源的现代压缩算法,压缩/解压速度出色,且能以精细的级别调节"速度 ↔ 压缩率"平衡。Compress 远程为 zstd 开放了 0 到 4 的级别范围:
| ZSTD 级别 | 含义 |
|---|---|
0 |
完全关闭压缩 |
1 |
最快压缩、压缩率最低 |
2(默认) |
速度与压缩率的良好平衡 |
3 |
压缩率更好,但 CPU 开销约为默认级的 2–3 倍 |
4 |
最高压缩率(CPU 开销最大) |
源码中 zstd 由 zstdModeHandler(backend/compress/zstd_handler.go)驱动,编码器来自 github.com/klauspost/compress/zstd:
writer, err := NewWriterSzstd(pipeWriter, zstd.WithEncoderLevel(zstd.EncoderLevel(f.opt.CompressionLevel)))
注意这里不是直接用裸 zstd 流,而是经 backend/compress/szstd_helper.go 封装成了 szstd(zstd-seekable-format):文件按 1 MiB 的分块独立压缩,并记录每块的压缩偏移量 BlockData 与原始大小,从而支持按需解压某一范围的数据而无需解压整个文件。
如何选择
- 追求兼容性:选 GZIP,任何解压工具都能直接打开产物文件;
- 追求速度与压缩率权衡:选 ZSTD,在 CPU 有限或文件极多时收益更明显;
- 如果你不确定级别,直接回车使用默认值即可:gzip 默认
-1(≈level 5),zstd 默认2。
存储到远程的文件:数据文件与元数据文件
当你用 rclone lsf 之类的命令直接查看底层远程时,会看到大量带压缩算法扩展名的文件(.gz、.zst)。官方文档特别强调了两条规则:
- 这些文件是标准的压缩文件,任何解压程序都可以打开并解压;
- 但它们携带 rclone 可用的隐藏元数据。你可以随意下载解压这些文件,但绝不要手动删除或重命名——缺少配套元数据文件的文件将无法被 rclone 识别。
从源码中可以还原出远程上的真实布局(backend/compress/compress.go#L46-L50):
gzFileExt = ".gz"
zstdFileExt = ".zst"
metaFileExt = ".json"
uncompressedFileExt = ".bin"
也就是说,上传一个名为 log.txt 的文件后,在底层远程中实际会看到两类对象:
- 数据文件:
log.txt.<base64原始大小>.gz(或.zst),存放压缩后的内容; - 元数据文件:
log.txt.json,存放 JSON 格式的ObjectMetadata(backend/compress/compress.go#L1073-L1081),记录压缩模式、原始大小、原始文件 MD5、MIME 类型,以及用于随机读取的压缩块元数据:
type ObjectMetadata struct {
Mode int // Compression mode of the file.
Size int64 // Size of the object.
MD5 string // MD5 hash of the file.
MimeType string // Mime type of the file
CompressionMetadataGzip *sgzip.GzipMetadata // Metadata for Gzip compression
CompressionMetadataZstd *SzstdMetadata // Metadata for Zstd compression
}
元数据对象与数据对象是成对管理的:Object 同时持有数据对象与元数据对象(backend/compress/compress.go#L1084-L1091);执行删除时 Object.Remove 会同时移除元数据文件与数据文件;执行 ChangeNotify 监视时,只跟踪元数据文件的变更(因为哈希就藏在元数据里)。
命名规则:文件名中的 base64 大小
官方文档说明了命名规则:压缩文件名形如 *.###########.gz,其中 * 是原始文件名,# 部分是未压缩文件大小的 base64 编码。更精确地讲:
- 8 字节原始大小的整型按小端序编码,再用 base64 URL 安全编码(无填充) 表示,因此固定是 11 个字符(backend/compress/compress.go#L297-L311);
- 用于解析文件名(以及去掉大小段)的正则是
^(.+?)\.([A-Za-z0-9-_]{11})$(backend/compress/compress.go#L59)。
文件名中编码原始大小有一个重要原因:它让 rclone 在不下载整个文件的情况下,仅凭文件名即可获知原始文件大小,从而在 List、Size() 等操作中免于拉取元数据。同理,官方要求"文件名不应由 rclone 压缩后端以外的任何东西更改"——改名会破坏这一信息,导致无法识别。
另外值得注意的是:并非所有文件都会被压缩。上传流程会先做可压缩性启发式判断:取前 1 MiB(heuristicBytes = 1048576)数据进行试压缩,只有当 原始字节数 / 压缩后字节数 > 1.1(minCompressionRatio,见 backend/compress/compress.go#L42-L44)时才会真正压缩;否则文件以 .bin 扩展名原样存储,返回的"原始大小"用哨兵值 -2 表示(backend/compress/compress.go#L313-L336)。这一点从 uncompressedModeHandler(backend/compress/uncompressed_handler.go)中 isCompressible 恒返回 false 也能印证。
配置项速查
以下选项在 rclone config 中配置,同时也可通过 rclone config create 命令或环境变量设置。下文以官方文档的选项说明为准,并给出源码注册信息(backend/compress/compress.go#L83-L121)作为补充。
标准选项
--compress-remote(必填)
- Config 键:
remote - 环境变量:
RCLONE_COMPRESS_REMOTE - 类型:string
- Required:true
要被压缩的底层远程,支持 remote: 或 remote:subdir 形式。
--compress-mode
- Config 键:
mode - 环境变量:
RCLONE_COMPRESS_MODE - 类型:string
- 默认值:
"gzip" - 可选值:
gzip— Standard gzip compression with fastest parameters.zstd— Zstandard compression — fast modern algorithm offering adjustable speed-to-compression tradeoffs.
源码将 mode 字符串映射为整型常量 Uncompressed=0 / Gzip=2 / Zstd=4,再据此选择对应 handler(backend/compress/compress.go#L285-L295);遇到无法识别的模式名会被当作 Uncompressed 处理,行为上等同"存储但不压缩"。
--compress-level(必填)
- Config 键:
level - 环境变量:
RCLONE_COMPRESS_LEVEL - 类型:string(提示文本随 mode 变化,具体级别说明见上文两个算法小节)
- Required:true
交互式向导会根据所选 mode 展示对应的级别说明文本。注意:虽然配置键类型为 string,但最终解析进 Options.CompressionLevel int(backend/compress/compress.go#L167-L172)供各 handler 使用。
高级选项
--compress-ram-cache-limit
- Config 键:
ram_cache_limit - 环境变量:
RCLONE_COMPRESS_RAM_CACHE_LIMIT - 类型:SizeSuffix
- 默认值:
20Mi
部分远程(如不支持流式上传、需要预先知道文件大小的后端)不允许上传大小未知的文件。此时压缩后文件的真实大小要到压缩完成后才能确定,因此需要先把压缩结果缓存起来以确定其大小。此参数用于决定缓存介质:
- 小于该上限的文件在 RAM 中缓存;
- 大于该上限的文件在磁盘上缓存。
对应实现是 Fs.rcat(backend/compress/compress.go#L561-L606):先用上限大小的缓冲区读取,若文件较小则直接在内存中走普通 Put;否则检查底层远程是否支持 PutStream 流式上传,支持则流式上传,不支持则在磁盘创建临时文件(os.CreateTemp("", "rclone-press-"))缓存后转普通上传。
--compress-description
- Config 键:
description - 环境变量:
RCLONE_COMPRESS_DESCRIPTION - 类型:string
- Required:false
该远程的描述信息,属于 rclone 各后端通用的描述字段,不参与压缩逻辑。
元数据支持
Compress 会透传读写底层远程支持的任何元数据(metadata)。当底层后端支持时,fs.RegInfo.MetadataInfo 声明 "Any metadata supported by the underlying remote is read and written"(backend/compress/compress.go#L80-L82)。关于 rclone 元数据机制的完整说明见仓库的 Metadata 文档(对应官方文档中的 metadata 页面)。
透明读写背后的源码工作流
上传(Put):先判可压缩性,再决定"压缩上传"还是"原样上传"
Fs.Put 的流程是(backend/compress/compress.go#L729-L746):
- 若目标对象已存在,则转为其
Update流程; - 否则调用
checkCompressAndType(backend/compress/compress.go#L517-L534),读取前 1 MiB 数据:用mimetype.Detect判定 MIME 类型,并用当前 mode 的 handler 试压缩计算压缩比; putWithCustomFunctions根据判定结果走putCompress(压缩上传)或putUncompress(以.bin原样上传);- 数据上传成功后,校验源声明的字节数与实际压缩得到的原始大小一致——因为文件名内嵌了原始大小,大小不匹配会导致文件无法再被正确读取,此时会删除已上传的对象并报错;
- 最后
putMetadata把 JSON 元数据写入*.json对象;若元数据上传失败,会回滚删除数据对象。
压缩上传本身也值得关注:gzip/zstd handler 内用 io.Pipe() + 独立 goroutine 边压缩边上传,并在压缩同时用 io.TeeReader 计算原始数据的 MD5 存进元数据。Fs.Hashes() 只声明 MD5(backend/compress/compress.go#L794-L797),而读取哈希时直接返回元数据里存好的原始文件 MD5——这是对外表现为"哈希仍可用"的原因。
下载(Open):只解压所需部分
Object.Open(backend/compress/compress.go#L1345-L1369)的路径为:
- 未压缩模式(
.bin)直接透传给底层对象; - 压缩模式则解析
SeekOption/RangeOption得到 offset 与 limit,使用chunkedreader(初始块 256 KiB、最大块 8 MiB,见 backend/compress/compress.go#L37-L40)读取底层数据,再交给对应 handler:- gzip:offset 为 0 时用
sgzip.NewReader顺序解压;offset 非 0 时用sgzip.NewReaderAt借助块索引定位到目标位置附近开始解压(backend/compress/gzip_handler.go#L53-L81); - zstd:使用
szstd的块表(SzstdMetadata.BlockData)精确定位到需要解压的 1 MiB 块,并行解码所需块后按序拼接,从而实现真正的随机范围读取(backend/compress/szstd_helper.go#L188-L318)。
- gzip:offset 为 0 时用
正因为随机读取能力的存在,rclone cat --offset、rclone serve、mount 等依赖 range 请求的场景在 Compress 远程上也能正常工作——这也解释了为什么元数据中必须保存每块的压缩偏移量与原始大小。
其他行为:服务端复制/移动、特性掩码与目录操作
Fs 注册了大量可选接口(见 backend/compress/compress.go#L1509-L1531),例如 Copy、Move、DirMove、Purge、About、CleanUp、PublicLink、ChangeNotify 等。其策略是:
- 多数操作直接透传给底层远程(例如
Mkdir、Rmdir、Precision); Copy/Move需要特殊处理,因为压缩对象涉及数据文件与元数据文件一对对象的同步拷贝/移动,且文件名受原始大小影响,重名对象需先删除旧文件,所以 rclone 优先尝试底层远程的服务端Copy/Move能力;- 特性列表通过
Fill → Mask → WrapsFs与底层远程做"与"运算(backend/compress/compress.go#L254-L272),并对"需要底层支持服务端 Move 才可用的PutStream"做了特殊裁剪; - 值得一提的还有
Fs.PutStream:当发现旧对象是压缩的或新内容可压缩时,上传完成后需要借助operations.Move把对象重命名为携带正确大小的文件名(backend/compress/compress.go#L748-L784)。
目录列表:隐藏实现细节
List/ListR/ListP 都会经过 processEntries(backend/compress/compress.go#L404-L420)对底层条目做"翻译":
.json元数据文件在列表中被隐藏(数据文件才是真实对象);- 数据文件被解析回原始文件名,并以"newObjectSizeAndNameOnly"的方式优先用文件名内嵌的原始大小构建对象;只有真正访问(下载、查哈希、看元数据)时才按需加载 JSON 元数据(懒加载,见
loadMetadataIfNotLoaded)。
这正是用户在 compress: 路径下看到的是"干净"的原始目录结构、而直接看底层远程却满是 .gz/.zst/.json 的原因。
验证与测试
仓库通过 backend/compress/compress_test.go 对后端进行验证:
TestIntegration走通用集成测试套件fstests.Run;TestRemoteGzip与TestRemoteZstd分别以本地临时目录为底层,创建type=compress、remote=<tempdir>、mode=gzip/level=-1与mode=zstd/level=2的配置并跑完整测试集,覆盖了两种压缩模式下的文件系统接口一致性。
如果你在本地构建了 rclone,也可以用命令直接体验,例如把本地目录压缩进 S3:
rclone config create press compress remote mys3:bucket/press mode gzip level -1
rclone copy ./logs press:archive-logs
rclone lsf press:
第一条命令用非交互方式创建名为 press 的 Compress 远程;第二条命令上传时会自动执行"可压缩性判断 → 压缩/原样 → 写入数据与元数据"的完整链路;第三条命令列出时看到的将是原始文件名而非 .gz 文件。
使用注意事项小结
- 不要手动删除/重命名底层远程上的
.gz/.zst/.json文件:.json是 rclone 解析的关键,数据文件与元数据文件必须成对存在; - 底层远程必须用其它工具单独查看时,请把它视为"压缩后的仓库",任何绕过 rclone 的写操作都可能导致列表中出现无法识别的孤儿文件;
- 对本已高度压缩的文件(图片、视频、已压缩归档),上传前会被启发式判定为"不可压缩"并原样存储为
.bin,这是设计使然,可避免无谓的 CPU 开销; - 若底层远程不支持未知大小上传,请留意
--compress-ram-cache-limit对内存/磁盘占用的影响; - 该远程仍属实验特性,涉及重要数据时应先小规模验证并保留原始副本。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00