Bazel Remote Caching

本文介绍Bazel远程缓存的基本概念与使用方法,包括搭建远程缓存服务器、配置Bazel以使用远程缓存、远程缓存的读写操作等。此外,还探讨了常见的问题及解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文翻译自:https://docs.bazel.build/versions/master/remote-caching.html

如有错误,敬请指正!

远程缓存

远程缓存,用于开发组内部或持续集成(CI )系统内,进行构建输出的共享。如果你的构建是需要反复执行的,一台机器的输出能够被另外一台机器安全的重用,那么这将会使构建速度显著的提升。

远程缓存概述

Bazel将整个构建拆分成独立的步骤,称之为构建动作。每个构建动作都有输入,输出名字,命令行和环境变量。必要的输入和期望的输出,在每个构建动作中都被显示的声明出来。

你可以为这些构建步骤的输出结果,搭建一套远程缓存服务器。这些输出由一系列的输出文件名和这些文件内容的hash组成。你可以通过远程缓存,重用其他用户的构建输出,而不是每次都为新的改动,在本地构建出新的输出。

怎样使用远程缓存:

  • 搭建一套服务器作为后端缓存
  • 配置Bazel构建,以使用远程缓存
  • 使用Bazel版本0.10.0或更高版本

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

  • 构建动作缓存,一个map表,由构建动作的哈希和构建动作的结果元数据组成。
  • 输出文件内容的可查找存储content-addressable store (CAS)。

构建如何使用远程缓存

一旦缓存服务器建立,可以通过如下多种方式来使用:

  • 从远程缓存进行读、写操作
  • 从远程缓存进行读、写操作,某些特定的目标除外
  • 从远程缓存只读
  • 不使用远程缓存

当你使用远程读、写缓存,进行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上可以通过Homebrew来完成:

 

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

 

下面是一个nginx配置的例子。注意,你需要将/path/to/cache/dir替换为一个合法的目录,且nginx对该目录有读写权限。你可能还需要将选项client_max_body_size,修改为较大的值,如果你有很大的输出文件。同时,服务器也需要其他配置,如鉴权。

nginx.conf中,server section的配置示例:

location ~ /( ac |cas) {
# The path to the directory where nginx should store the cache contents.
root /www/cache;
# 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 Cache

Bazel远程缓存是一个开源的远程构建缓存服务,你可以在框架中使用。不过,它是实验性的,也不提供支持服务。

该缓存服务,将内容存储在磁盘上,还提供了垃圾收集功能,用于强制设置存储上限和清理无用产出。该缓存服务已被制作为一个docker镜像,它的代码也可以在GitHub上找到。

请参考GitHub上的使用说明,进行使用。

Google Cloud Storage

Google Cloud Storage是一个完全管理的对象存储,它提供了符合Bazel远程缓存的HTTP API接口。它需要你已充值的Google云账号。

使用Google Cloud Storage作为缓存:

  1. 创建一个存储箱。确保你选择的箱子位置是离你最近的,因为网络带宽对远程缓存很重要。
  2. 创建一个Bazel到Cloud Storage鉴权用的服务账号。参考创建服务账号
  3. 产生一个JSON格式的密钥,给Bazel做鉴权使用。安全的保存该密钥,因为任何拿到这个密钥的人,都可以从GCS存储箱中读写数据。
  4. 通过如下Bazel命令行,连接上Cloud Storage:
    通过参数:--remote_http_cache=https://storage.googleapis.com/bucket-name 将URL传递给Bazel。这里的bucket-name是你自己的存储箱。
    通过参数:--google_credentials=/path/to/your/secret-key.json,将鉴权密钥,传递给Bazel。
  5. 你可以配置Cloud Storage自动删除老文件。参考:管理对象生命周期

Other Servers

你可以搭建任意支持PUT和GET的HTTP/1.1服务器,当做缓存后端。有用户反馈他们已经使用HazelcastApache httpd, and AWS S3,成功的搭建了缓存后端服务。

鉴权

自0.11.0版本开始,Bazel添加了HTTP基础鉴权功能。你可以将用户名和密码,通过远程缓存URL传递给Bazel。具体的语法是这样的,https://username:password@hostname.com:port/path。请注意,HTTP基础鉴权,会将用户名和密码,以明文的方式在网络上传输,所以务必一直使用HTTPS协议。

HTTP远程缓存协议

Bazel通过HTTP/1.1支持远程缓存。该协议是个比较简单的概念:二进制数据Binary data (BLOB)是通过PUT请求上传数据,通过GET请求下载数据。构建动作的结果元数据,存储在/ac/路径下,输出文件存储在/cas/路径下。

例如:某个远程缓存服务运行在http://localhost:8080/cache下。一个下载构建动作(SHA256哈希01ba4719...)结果元数据的Bazel请求,看起来是下面这样的:

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

一个上传构建动作(SHA256哈希15e2b0d3...)结果元数据到CAS的Bazel请求,看起来是下面这样的:

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

0x310x320x330x340x350x360x370x380x39

使用远程缓存方式运行Bazel

远程缓存服务搭建完成后,你需要通过给Bazel命令添加参数,来使用远程缓存。参考配置清单和如下参数。

你可能需要配置鉴权,这取决于你选择的服务器。

你可以通过将这些参数,添加到.bazelrc中,这样,你就不需要每次运行Bazel的时候,都指定这些参数。根据你的工程和团队灵活性,你可以将这些参数放置在下面这些位置的.bazelrc文件里。

  • 本地机器
  • 工程目录下,团队内共享
  • CI系统内

在远程缓存上读和写

注意控制好往远程缓存上的写权力。可能只有你的CI系统,有能力去写远程缓存。

用下面的参数进行配置:

  • 从远程缓存上读数据,写数据到远程缓存
  • 禁用沙箱功能

 

build --spawn_strategy=remote --genrule_strategy=remote
build --strategy=Javac=remote --strategy=Closure=remote
build --remote_http_cache=http: //replace-with-your .host:port

 

通过沙箱功能使用远程缓存是试验性的。通过如下参数,开启远程缓存的读、写沙箱功能。

 

build --experimental_remote_spawn_cache
build --remote_http_cache=http: //replace-with-your .host:port

 

只读远程缓存

通过下面的参数,设置只读远程缓存,并关闭沙箱功能。

build --spawn_strategy=remote --genrule_strategy=remote
build --strategy=Javac=remote --strategy=Closure=remote
build --remote_http_cache=http: //replace-with-your .host:port
build --remote_upload_local_results= false

沙箱使用远程缓存是实验性的。通过下面的参数,开启沙箱远程缓存只读功能。

build --experimental_remote_spawn_cache
build --remote_http_cache=http: //replace-with-your .host:port
build --remote_upload_local_results= false

从使用远程缓存中,剔除特定目标

将目标标记为no-cache,即可将指定的目标剔除出使用远程缓存列表。例如:

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

从远程缓存中,删除内容

从远程缓存中,删除内容,是你服务管理的一部分。怎样删除内容,取决于你的缓存服务器。当删除输出时,要么整个输出缓存删除,要么删除老的输出缓存。

输出缓存是以一个名字和哈希的集合方式存储的。当删除内容是,没有办法区分出,某个输出属于哪个特定的构建。

你可以用如下方式删除缓存:

  • 当缓存被污染后,创建一块新的缓存
  • 通过删除老缓存的方式,减少存储的数量

已知问题

Bazel编译时,不能进行文件修改

在构建时,如果某输入文件有改动,Bazel会将非法的结果上传到远程缓存。我们正致力于解决此问题。关注issue #3360的更新。可以通过不修改文件的方式,规避该问题。

环境变量泄露到构建动作中

构建动作中包含环境变量。这会导致多台机器间共享远端缓存的命中问题。例如:不同环境配置了不同的$PATH环境变量,将不共享缓存命中。你可以通过--experimental_strict_action_env,确保不会出现该问题。仅允许--action_env配置的环境变量白名单,可以包含在构建动作定义里面。Bazel的Debian/Ubuntu包中,通过/etc/bazel.bazelrc,定义环境变量白名单,里面就包含了$PATH。如果你发现缓存命中率没有达到预期,检查下是不是你又一个较老的/etc/bazel.bazelrc文件。

Bazel不跟踪工作空间外的工具

Bazel目前不跟踪工作空间外的工具。这可能产生问题,例如,一个构建动作使用了/usr/bin/目录下的编译器。然后,两个不同用户装了不同的编译器,将会错误的共享缓存命中,因为他们的输出不同,但是却又相同的构建动作hash。请关注issue #4558的更新。

外部链接

  • 你的构建在数据中心:Bazel团队在FOSDEM 2018提出了一个话题,关于远端缓存和执行
  • 使用远程缓存,进行更快的Bazel构建:基线测试:Nicolò Valigi写了个博客,关于他做的远程缓存Bazel构建。

Bazel远程执行(开发中)

基于gRPC协议的远程缓存和远程执行正在开发中。远程执行允许Bazel在一个独立空间执行构建动作,比如数据中心。你可以尝试在Buildfarm上尝试远程执行,这是个开源的项目,致力于提供一个分布式的远程执行平台。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值