Cloudflare 用缓存转码压缩磁盘内容,探索把缓存容量“变大”

2026-09-13 23 预计阅读时间: 1 分钟
来源: infoq.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:8 分钟

缓存系统的瓶颈不一定是命中率,也可能是磁盘空间。Cloudflare 最近介绍了一项名为 Cache Transcoding 的原型方案:对象进入磁盘缓存前,先对符合条件的内容进行压缩,读取时再解压返回。目标很直接,在不增加物理磁盘的情况下,让现有缓存承载更多有效内容。

这项技术主要面向原本没有压缩的文本内容,例如 HTML、JSON、CSS 和 JavaScript。Cloudflare 估计,若方案在更大范围内验证成功,可能带来 PB 级的额外有效缓存容量。不过目前仍处于原型和测试阶段,实际收益取决于内容类型、压缩比、CPU 消耗以及缓存访问模式。

缓存转码解决的是什么问题

传统缓存通常把源站响应直接写入磁盘。对于图片、视频等已经经过编码或压缩的数据,这种做法较为合理;但对于未压缩文本,磁盘中保存的内容可能远大于网络传输所需的体积。

例如,一份 1 MB 的 JSON 文件可能通过 gzip 或 Brotli 传输后只有几百 KB,但缓存层仍可能把 1 MB 原文写入磁盘。如果缓存规模达到数十亿个对象,原文和压缩内容之间的差额就会变成可观的存储成本。

Cache Transcoding 的基本路径可以概括为:

  1. 请求返回内容进入缓存流程。
  2. 系统判断对象是否属于适合压缩的类型。
  3. 对 HTML、JSON、CSS、JavaScript 等文本执行 Zstandard 压缩。
  4. 将压缩后的对象写入磁盘,并保存必要的元数据。
  5. 命中缓存时读取压缩对象,解压后提供给后续响应处理。

这里的关键点是“缓存内部格式”和“客户端响应格式”可以分离。缓存不必永久保存源站返回的原始字节,只要能够可靠地恢复响应内容以及相关元数据即可。

为什么选择 Zstandard

Zstandard,简称 zstd,是一种面向通用数据压缩的算法,通常在压缩率和解压速度之间提供较好的平衡。对于缓存系统而言,解压路径尤其重要,因为热点对象可能被频繁读取,解压延迟和 CPU 占用会直接影响请求处理能力。

与传统的磁盘压缩相比,面向缓存的转码还需要处理更多工程问题:

  • 内容资格判断:已经压缩的 JPEG、PNG、MP4、ZIP 等对象通常没有必要再次压缩。
  • 响应兼容性:压缩是缓存内部行为,不能错误地改变 Content-EncodingContent-Length 或范围请求语义。
  • 版本与回滚:缓存格式变化后,旧缓存对象是否可读、如何失效,都需要明确策略。
  • CPU 预算:压缩发生在写入路径,解压发生在读取路径,两者都需要纳入节点资源规划。
  • 失败处理:压缩失败、元数据损坏或格式版本不兼容时,应能回退或丢弃对象,而不是影响正常请求。

因此,这并不是简单地给缓存目录执行一次压缩命令。它更接近一种带有对象格式、索引和生命周期管理的存储层改造。

可以怎样在本地验证收益

下面的命令可以用于一个小型实验。它假设当前目录中有待评估的文本文件,并且系统已经安装了 zstd。这不是 Cloudflare 的生产配置,而是帮助团队估算压缩率和 CPU 成本的可复制方法。

先创建测试文件并压缩:

# macOS: brew install zstd
# Debian/Ubuntu: sudo apt-get install zstd

mkdir -p cache-lab
cp ./response.json cache-lab/response.json

/usr/bin/time -f 'compress: %e sec, %M KB max RSS' \
  zstd -q -3 --long=27 \
  -o cache-lab/response.json.zst \
  cache-lab/response.json

ls -lh cache-lab/response.json cache-lab/response.json.zst

检查压缩文件是否可以无损恢复:

zstd -q -d \
  -o cache-lab/response.restored.json \
  cache-lab/response.json.zst

cmp cache-lab/response.json cache-lab/response.restored.json
printf 'restore verification: OK\n'

还可以批量估算一组缓存对象的收益:

find ./cache-samples -type f \
  \( -name '*.html' -o -name '*.json' -o -name '*.css' -o -name '*.js' \) \
  -print0 | while IFS= read -r -d '' file; do
    zstd -q -3 -c -- "$file" > "$file.zst"
  done

du -sb ./cache-samples > /tmp/cache-original.bytes
find ./cache-samples -type f -name '*.zst' -print0 \
  | xargs -0 du -cb \
  | tail -n 1

实验时不要只记录压缩率,还应同时记录压缩和解压耗时、峰值内存、对象大小分布以及不同内容类型的结果。小文件尤其值得单独观察,因为压缩帧和索引元数据可能抵消部分收益。

落地时需要建立的边界

Cache Transcoding 的价值取决于缓存命中对象是否足够多、未压缩文本比例是否足够高,以及节点是否有可用 CPU。对于已经使用 Brotli、gzip 或媒体编码的内容,重复压缩往往收益有限,甚至可能增加处理成本。

一个稳妥的采用路径可以是:

  1. 只选择明确的文本 MIME 类型,并排除小对象。
  2. 在低压缩级别开始,优先控制延迟和 CPU。
  3. 为压缩前后大小、压缩耗时、解压耗时和缓存命中率增加指标。
  4. 采用版本化的缓存对象格式,允许逐步失效旧对象。
  5. 在故障时允许跳过压缩或直接删除无法读取的缓存对象。
  6. 对范围请求、条件请求、内容校验和缓存变体进行专项测试。

这项原型的启发并不是“所有缓存都应该压缩”,而是缓存层可以像数据库存储引擎一样,针对访问模式和数据形态选择内部表示。若压缩带来的有效容量提升能够覆盖额外 CPU 和实现复杂度,那么它可能成为扩展缓存规模的一种方式;在更广泛的测试完成前,仍应把它视为需要验证的工程方案,而不是已经普遍可用的特性。


相关推荐