远程缓存

<ph type="x-smartling-placeholder"></ph> 报告问题 <ph type="x-smartling-placeholder"></ph> 查看来源 敬上 每晚 · 7.3。 · 7.2 条 · 7.1 · 7.0。 · 6.5

本页将介绍远程缓存、设置服务器以托管缓存,以及 使用远程缓存运行构建。

远程缓存由开发者团队和/或持续集成系统使用 (CI) 系统共享构建输出。如果您的 build 可重现, 只要有一台机器的输出 就能安全地在另一台机器上重复利用 显著加快构建速度。

概览

Bazel 将构建拆分为多个离散的步骤,这些步骤称为操作。每项操作 包含输入、输出名称、命令行和环境变量。是否必需 需要为每个操作明确声明输入和预期输出。

您可以将服务器设置为构建输出的远程缓存, 操作输出。这些输出包括一系列输出文件名和 其内容的哈希值。借助远程缓存,您可以重复使用构建输出 从其他用户的 build 复制而来,而不是在本地构建每个新的输出。

如需使用远程缓存,请执行以下操作:

  • 将服务器设置为缓存的后端
  • 将 Bazel 构建配置为使用远程缓存
  • 使用 Bazel 0.10.0 或更高版本

远程缓存存储两种类型的数据:

  • 操作缓存,即操作哈希与操作结果元数据的映射。
  • 输出文件的内容可寻址存储 (CAS)。

请注意,远程缓存还会针对每个 操作。因此,检查 Bazel 的 stdout/stderr 并不是 估算缓存命中数

构建如何使用远程缓存

将服务器设置为远程缓存后,您可以将该缓存用于多个 方式:

  • 读取和写入远程缓存
  • 对远程缓存执行读取和/或写入操作(特定目标除外)
  • 仅从远程缓存读取
  • 完全不使用远程缓存

在运行可以读取和写入远程缓存的 Bazel 构建时 构建过程会遵循以下步骤:

  1. Bazel 会创建需要构建的目标的图表,然后创建 所需操作的列表。所有这些操作都声明了输入 和输出文件名。
  2. Bazel 会检查本地机器上的现有构建输出,并重复使用 找到的内容。
  3. Bazel 会检查缓存中是否存在现有构建输出。如果能找到输出结果 Bazel 会检索输出。这是一次缓存命中。
  4. 对于未找到输出的必要操作,Bazel 会执行 操作并创建所需的构建输出。
  5. 新的构建输出将上传到远程缓存。

将服务器设置为缓存的后端

您需要设置一台服务器来充当缓存的后端。HTTP/1.1 服务器可以将 Bazel 的数据视为不透明字节 可用作远程缓存后端。Bazel 的 HTTP 缓存协议是支持远程 缓存。

你负责选择、设置和维护后端 用于存储缓存输出的服务器。选择服务器时,请考虑以下因素:

  • 网速。例如,如果您的团队在同一个办公室,您可能 运行自己的本地服务器
  • 安全性。远程缓存将包含您的二进制文件,因此需要是安全的。
  • 易于管理。例如,Google Cloud Storage 是一项全代管式服务。

可用于远程缓存的后端有很多。选项包括:

nginx

nginx 是一种开源 Web 服务器,借助其 [WebDAV 模块], 用作 Bazel 的远程缓存在 Debian 和 Ubuntu 上,你可以安装 nginx-extras 软件包。在 macOS 上,nginx 可通过 Homebrew 进行访问:

brew tap denji/nginx
brew install nginx-full --with-webdav

以下是 nginx 的配置示例。请注意,您需要 将 /path/to/cache/dir 更改为 nginx 具有权限的有效目录 读写。您可能需要将 client_max_body_size 选项更改为 。服务器需要其他 例如身份验证

nginx.confserver 部分的配置示例:

location /cache/ {
  # The path to the directory where nginx should store the cache contents.
  root /path/to/cache/dir;
  # Allow PUT
  dav_methods PUT;
  # Allow nginx to create the /ac and /cas subdirectories.
  create_full_put_path on;
  # The maximum size of a single file.
  client_max_body_size 1G;
  allow all;
}

bazel-remote

bazel-remote 是一个开源远程构建缓存,可用于 基础架构已成功用于生产环境中的 多家公司。请注意,Bazel 项目会 不为 bazel-remote 提供技术支持。

此缓存将内容存储在磁盘上,并提供垃圾回收 强制执行存储空间上限并清理未使用的工件缓存 作为 [docker 映像] 提供,其代码可在 GitHub REST 和 gRPC 远程缓存 API 均受支持。

参阅 GitHub 页,了解有关使用方法的说明。

Google Cloud Storage

[Google Cloud Storage] 是一个全托管式对象存储, 与 Bazel 的远程缓存协议兼容的 HTTP API。它需要 拥有已启用结算功能的 Google Cloud 账号。

如需使用 Cloud Storage 作为缓存,请执行以下操作:

  1. 创建存储分区。 请务必选择离您最近的存储分区位置,例如网络带宽 对远程缓存非常重要

  2. 为 Bazel 创建一个服务账号,以便向 Cloud Storage 进行身份验证。请参阅 创建服务账号

  3. 生成一个密钥 JSON 密钥,然后将其传递给 Bazel 进行身份验证。商店 拥有密钥的任何人都可以读取和写入任意数据 GCS 存储分区之间的数据。

  4. 通过将以下标志添加到 Bazel 命令来连接到 Cloud Storage:

    • 使用标志将以下网址传递给 Bazel: --remote_cache=https://storage.googleapis.com/bucket-name,其中 bucket-name 是您的存储分区的名称。
    • 使用以下标志传递身份验证密钥:--google_credentials=/path/to/your/secret-key.json,或 --google_default_credentials 以使用应用身份验证
  5. 您可以将 Cloud Storage 配置为自动删除旧文件。为此,请参阅 管理对象生命周期

其他服务器

您可以将任何支持 PUT 和 GET 的 HTTP/1.1 服务器设置为缓存 后端。有用户报告称,Hazelcast 等缓存后端的 Apache httpdAWS S3

身份验证

从 0.11.0 版开始,Bazel 中添加了对 HTTP 基本身份验证的支持。 您可以通过远程缓存网址将用户名和密码传递给 Bazel。通过 语法为 https://username:[email protected]:port/path。请注意, HTTP 基本身份验证通过 因此始终将其与 HTTPS 结合使用至关重要

HTTP 缓存协议

Bazel 支持通过 HTTP/1.1 进行远程缓存。该协议在概念上很简单: 二进制数据 (BLOB) 通过 PUT 请求上传,并通过 GET 请求下载。 操作结果元数据存储在路径 /ac/ 下,而输出文件则存储在 位于路径 /cas/ 下。

例如,假设在 http://localhost:8080/cache 下运行远程缓存。 运行 SHA256 的 Bazel 请求,用于下载某个操作的操作结果元数据 哈希 01ba4719... 将如下所示:

GET /cache/ac/01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b HTTP/1.1
Host: localhost:8080
Accept: */*
Connection: Keep-Alive

将具有 SHA256 哈希 15e2b0d3... 的输出文件的 Bazel 请求 CAS 将如下所示:

PUT /cache/cas/15e2b0d3c33891ebb0f1ef609ec419420c20e320ce94c65fbc8c3312448eb225 HTTP/1.1
Host: localhost:8080
Accept: */*
Content-Length: 9
Connection: Keep-Alive

0x310x320x330x340x350x360x370x380x39

警告:不使用 Bytes 构建 与 HTTP 缓存不兼容。为了最大限度地提升性能 请考虑改用 gRPC 缓存

使用远程缓存运行 Bazel

将服务器设置为远程缓存后,要使用 您需要向 Bazel 命令添加标志查看配置列表 标记。

您可能还需要配置身份验证,这是您的 所选服务器

您可能需要在 .bazelrc 文件中添加这些标志,这样就不会 每次运行 Bazel 时都需要指定它们具体取决于您的项目和 团队动态时,您可以向 .bazelrc 文件添加标志,该文件应符合以下要求:

  • 在本地计算机上
  • 在项目的工作区中,与团队共享
  • 在 CI 系统上

对远程缓存执行读写操作

注意谁能够写入远程缓存。你可能需要 只有 CI 系统才能写入远程缓存。

使用以下标志对远程缓存执行读写操作:

build --remote_cache=http://your.host:port

HTTP 之外,还支持以下协议:HTTPSgrpcgrpcs

除上述标志之外,还使用以下标志,以便仅从 远程缓存:

build --remote_upload_local_results=false

将特定目标从远程缓存中排除

要将特定目标排除使用远程缓存,请使用以下标记来标记目标: no-remote-cache。例如:

java_library(
    name = "target",
    tags = ["no-remote-cache"],
)

从远程缓存中删除内容

从远程缓存中删除内容是服务器管理工作的一部分。 从远程缓存中删除内容的方式取决于您使用的服务器 设置为缓存删除输出时,您要么删除整个缓存, 或删除旧输出项。

缓存的输出存储为一组名称和哈希值。删除时 因此无法区分哪些输出 build。

为了实现以下目的,您可能需要从缓存中删除内容:

  • 在缓存中毒后创建干净的缓存
  • 通过删除旧输出项来减少存储空间用量

Unix 套接字

远程 HTTP 缓存支持通过 unix 网域套接字进行连接。行为 类似于 curl 的 --unix-socket 标志。使用以下命令配置 unix 域套接字:

   build --remote_cache=http://your.host:port
   build --remote_proxy=unix:/path/to/socket

Windows 不支持此功能。

磁盘缓存

Bazel 可以将文件系统上的目录用作远程缓存。这是 在切换分支和/或工作时共享构建工件 同一项目的多个工作区,例如多次签出。开始时间 Bazel 不会对目录进行垃圾回收,您可能希望将 定期清理此目录请按如下方式启用磁盘缓存:

build --disk_cache=path/to/build/cache

您可以使用 ~ 别名将特定于用户的路径传递给 --disk_cache 标志 (Bazel 将替换为当前用户的主目录)。这个功能非常方便 通过项目的 已签入 .bazelrc 文件中。

已知问题

在构建期间修改输入文件

如果在构建期间修改输入文件,Bazel 可能会上传无效的 将结果发送到远程缓存。您可以使用 --experimental_guard_against_concurrent_changes 标志。那里 还不是已知问题,在未来版本中,该功能会默认启用。 请参阅 [问题 #3360] 了解更新。通常,请避免在 build。

环境变量泄露到操作中

操作定义包含环境变量。对于 在机器之间共享远程缓存命中。例如,具有 不同的 $PATH 变量不会共享缓存命中。仅环境变量 通过 --action_env 明确列入白名单的操作包含在操作中 定义。用于安装 /etc/bazel.bazelrc 的 Bazel Debian/Ubuntu 软件包 其中包含环境变量白名单(包括 $PATH)。如果您获得的 缓存命中数低于预期,请检查您的环境是否没有旧的 /etc/bazel.bazelrc 文件。

Bazel 不会跟踪工作区之外的工具

Bazel 目前不会跟踪工作区之外的工具。它可以是 例如,如果操作使用来自 /usr/bin/ 的编译器,就会出现问题。然后, 两个安装了不同编译器的用户会错误地共享缓存命中 因为输出不同,但它们具有相同的操作哈希值。请参阅 问题 4558

在 Docker 容器内运行构建时,会丢失内存中增量状态 即使在单个 Docker 容器中运行时,Bazel 也使用服务器/客户端架构。 在服务器端,Bazel 会维护内存中状态,从而加快构建速度。 在 Docker 容器内(例如在 CI 中)运行构建时,内存中状态会丢失 并且 Bazel 必须先重新构建,然后才能使用远程缓存。