在前两篇 bazel-remote 系列文章里,我们对比了 S3 后端与一致性哈希两种横向扩展方案,也给出过"分层缓存(L1 + L2)是最佳实践"的结论。但那个结论停留在架构层面——具体怎么配?数据到底怎么流动?性能如何保障?

本文就把这个"最佳实践"落到地面:剖析 bazel-remote 原生两级存储的工作原理,并给出可直接套用的命令行与 YAML 配置。

一、不是双写,是智能分层缓存

bazel-remote 原生支持同时配置本地磁盘和 S3 存储,这正是它实现"两级存储"或"分层缓存"的标准方式。

但需要澄清一个常见误解:它的实现机制并非简单的双写,而是一个优先级明确、自动流转的智能缓存体系。本地磁盘是主角,S3 是后盾——两者各司其职,协同流转。

二、两级存储架构与工作原理

核心架构是 “本地磁盘 (L1) + 远程 S3 (L2)”

读取流程:优先本地,未命中则回源

  1. 当请求一个缓存对象时,bazel-remote 首先检查本地磁盘缓存
  2. 如果本地命中,数据会立即返回不会与 S3 进行任何交互——这是延迟最低的快路径。
  3. 如果本地未命中,但配置了 S3 代理后端,它会自动从 S3 查询
  4. 一旦从 S3 成功获取到数据,它会被自动存入本地磁盘,以供后续请求快速访问——这次回源之后,下次就是本地命中。

写入流程:存入本地,异步上传

  1. 当有新缓存需要存储时,数据会首先写入本地磁盘——主请求在写盘完成后即可返回。
  2. 同时,该数据会被放入一个异步上传队列,在后台独立、并发地上传到 S3。
  3. 这个上传过程不会阻塞主请求,确保了响应速度。

异步上传行为可通过两个参数精细控制:

参数 默认值 作用
numUploaders 100 后台并发上传 goroutine 数
maxQueuedUploads 1,000,000 异步上传队列容量上限

设计要点:写本地是同步的(关乎响应延迟),传 S3 是异步的(关乎持久化与共享)。主流程永远不被 S3 的网络抖动拖累——这是这套机制能在生产环境稳定运行的关键。

三、配置方式

启动 bazel-remote 时,同时指定本地磁盘目录和 S3 相关参数即可启用两级存储。两种配置方式等价,按团队习惯选择。

命令行参数方式

 1bazel-remote \
 2    --dir /path/to/disk/cache \          # 指定本地磁盘缓存目录
 3    --max_size 100 \                     # 本地缓存最大容量 (GB)
 4    --s3.endpoint your-s3-endpoint \     # S3 服务端点
 5    --s3.bucket your-bucket-name \       # S3 存储桶名称
 6    --s3.prefix your-prefix \            # (可选) S3 对象键前缀
 7    --s3.auth_method access_key \        # 认证方式
 8    --s3.access_key_id YOUR_KEY \        # Access Key
 9    --s3.secret_access_key YOUR_SECRET   # Secret Key
10    # ... 其他参数

YAML 配置文件方式

 1# bazel-remote.yml
 2dir: /path/to/disk/cache
 3max_size: 100
 4
 5s3_proxy:
 6  endpoint: your-s3-endpoint:9000
 7  bucket: your-bucket-name
 8  prefix: your-prefix
 9  disable_ssl: true          # 内网可考虑禁用 SSL 以提升性能
10  auth_method: access_key
11  access_key_id: YOUR_KEY
12  secret_access_key: YOUR_SECRET

如果 S3 后端使用的是 RustFS,endpoint 指向 RustFS 服务地址即可,配置方式完全一致。RustFS 的部署可参考《用 Docker Compose 部署 RustFS:高性能 S3 兼容对象存储实战》。

四、为什么这是最佳实践

bazel-remote 的两级存储机制是一个设计精良的分层缓存方案,它把两种存储介质的优势拧到了一起:

  • 性能:通过 L1 本地磁盘保障了绝大多数缓存命中的极速响应——本地 NVMe 延迟通常在 1ms 以内
  • 持久性与共享:通过 L2 S3 存储实现了数据的持久化跨实例共享——实例宕机不丢数据,新实例可直接复用
  • 可靠性:异步上传机制确保了主流程的性能不受影响——即使 S3 短暂不可达,本地缓存仍能正常服务

这正是我们在《Bazel 远程缓存高可用部署:S3(RustFS)vs 一致性哈希延迟实测对比》中提到的"最佳实践:分层缓存(L1 + L2)"——它将两种方案的优势结合在了一起:本地磁盘的读取速度 + S3 的数据共享与持久性。

五、参数调优建议

默认参数(100 并发上传、百万级队列)对大多数场景已足够,但在高写入场景下可按需调整:

场景 调整方向 理由
CI/CD 并发构建多 numUploaders 调至 200~500 写入压力大,加快 S3 上传消化速度
本地磁盘容量受限 max_size 调小,依赖 S3 兜底 本地只放热数据,冷数据靠 S3 回源
S3 带宽受限 numUploaders 调小避免打满 防止上传洪峰影响 S3 服务稳定性
内网部署 disable_ssl: true 省去 TLS 握手开销,降低延迟

六、小结

两级存储不是"锦上添花",而是 bazel-remote 生产部署的标配形态。单用本地磁盘——没有持久化和共享;单用 S3——延迟妥协。只有两者协同,才能在不牺牲速度的前提下获得可靠性。

配置上只需多写一个 s3_proxy 块,成本极低,收益显著。如果你正在运行 bazel-remote,强烈建议按本文配置升级到两级存储。

参考