bazel远程缓存(Remote Cache)

原理

您可以将服务器设置为构建输出(即这些操作输出)的远程缓存。这些输出由输出文件名列表及其内容的哈希值组成。借助远程缓存,您可以重复使用其他用户的 build 中的构建输出,而不是在本地构建每个新输出。

增量构建极大的提升了本地研发的构建效率,但有些场合它的效果不是很好,例如 CI 环境通常采用“干净”的容器,此时没有上一次的构建数据,只能全量构建。

即使是本地研发,如果从远端同步代码时修改了全局参数,也会导致增量构建失效。

缓存 (Remote Cache) 与远程执行 (Remote Execution) 可以很好的解决这个问题。

前面聊到,Action 满足封闭性,即相同的 Action 信息一定产生相同的结果。因此可以建立 Action 到 ActionResult 的映射。为了便于索引,Bazel 把 Action 信息通过 sha256 哈希算法压缩成摘要 (Digest),把 Digest 到 ActionResult 的映射存储在云端,就可以实现 Action 的跨构建共享。

Action 共享示意图

这里的 Storage 是完全基于内容寻址的,即“一个 Digest 唯一对应一个 ActionResult”,内容寻址的好处是不容易污染存储空间,因为修改任何一行代码会计算出不同的 Digest,不用担心污染别人的 ActionResult。内容寻址的存储引擎,被称为Content Addressable Storage(CAS),如果没有特别强调,本文后续使用简称 CAS 来表述。

CAS 里存放的任何文件,无论是 Action 的 Meta 信息还是编译产物二进制,都被称为 Blob。

为保证 CAS 的存储空间被有效利用,通常会使用 LRU 算法管理 CAS 里存储的 Blob,当存储空间写满时,最久没被访问的 Blob 就会被自动淘汰,这样就保证了空间里的 Blob 是最活跃的。

部署

部署&运行

前面讲了Bazel的基本本地使用和原理,但是我们知道,Bazel最重要的是支持缓存和分布式(远程执行),那么这一节主要就是讲如何让bazel使用缓存。

要能够缓存Bazel每个action的输出,我们就要一个server来实现remote cache,用于存储action的输出。这些输出实际上是一堆文件输出对应的hash值。总体来说,我们需要满足三个前提:

  • 设置一个server作为cache backend

  • 配置Bazel build去使用cache

  • Bazel版本要在0.10.0以上

Cache本身会存储两种数据:

  • action cache,或者说实际上是一个acton->action result的map映射表

  • 一个可寻址(addressable)的输出文件存储系统

https://docs.bazel.build/versions/master/remote-caching.html 中对Bazel Remote Cache的使用和工作有更详细的介绍,就不重复了。这里直接讲到底怎么设置一个Bazel Remote Cache Server. 在上面这个链接中提到了三种方式:

  • NGINX的WebDAV模块

  • 开源的bazel-remote

  • Google Cloud Storage

这里我们直接选择第二种:开源的bazel-remote,以便可能的定制及更好理解内部实现。

buchgr/bazel-remote

这里我们不用去重新编译运行,直接下载对应的docker镜像并运行即可

$docker pull buchgr/bazel-remote-cache

bazel-remote支持grpc和http的接口调用,但注意docker内部应用的http接口应该是8080而不是9090(官方文档有误)。

创建一个目录cache, 然后启动docker容器如下

path=`pwd`;docker run -v $path/cache:/data -p 9090:8080 -p 9092:9092 buchgr/bazel-remote-cache

备注:

  • 需要提前创建cache目录或者失败后对目录加777权限,并用-u指定当前用户的uid和gid,否则会报mkdir /data/cas.v2:permission denied。即docker run -u $uid:$gid -v xxx

  • 建议用--max_size限制缓存目录的大小。一般在命令最后加上 --maz_size=50

我们可以看到一堆输出:

2020/10/13 16:12:20 bazel-remote built with go1.14.5 from git commit cc9030667416ab63d89b9fbf543f0243292009b4.
2020/10/13 16:12:20 Initial RLIMIT_NOFILE cur: 1048576 max: 1048576
2020/10/13 16:12:20 Setting RLIMIT_NOFILE cur: 1048576 max: 1048576
2020/10/13 16:12:21 Migrating files (if any) to new directory structure: /data/ac
2020/10/13 16:12:21 Migrating files (if any) to new directory structure: /data/cas
2020/10/13 16:12:21 Loading existing files in /data.
2020/10/13 16:12:23 Sorting cache files by atime.
2020/10/13 16:12:23 Building LRU index.
2020/10/13 16:12:23 Finished loading disk cache files.
2020/10/13 16:12:23 Loaded 0 existing disk cache items.
2020/10/13 16:12:23 Starting HTTP server on address :8080
2020/10/13 16:12:23 HTTP AC validation: enabled
2020/10/13 16:12:23 Starting HTTP server for profiling on address :6060
2020/10/13 16:12:23 Starting gRPC server on address :9092
2020/10/13 16:12:23 gRPC AC dependency checks: enabled
2020/10/13 16:12:23 experimental gRPC remote asset API: disabled
然后可以通过其/status接口来查看是否正常启动
$curl http://localhost:9090/status
{"CurrSize": 0,"MaxSize": 5368709120,"NumFiles": 0,"ServerTime": 1602605641,"GitCommit": "cc9030667416ab63d89b9fbf543f0243292009b4"
}

另外我们也可以查看cache目录下是否生成了对应文件:

​这时就可以在运行bazel build的时候指定remote cache server的地址:

$bazel build //src/main:app --remote_cache=http://localhost:9090
INFO: Invocation ID: a9a389d2-1e9f-4878-b65b-586e7b70fa35
INFO: Analyzed target //src/main:app (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
Target //src/main:app up-to-date:bazel-bin/src/main/app_deploy.jarbazel-bin/src/main/app_unsigned.apkbazel-bin/src/main/app.apk
INFO: Elapsed time: 3.271s, Critical Path: 3.02s
INFO: 12 processes: 9 darwin-sandbox, 3 worker.
INFO: Build completed successfully, 13 total actions

备注:

为了避免本地缓存对远程缓存的影响,在执行构建前清理本地缓存。运行以下命令可删除输出文件,并可选择停止服务器。:

bazel clean

检查缓存命中率

在 Bazel 运行的标准输出结果中,查看列出进程的 INFO 行,该进程大致对应于 Bazel 操作。运行操作所在的行详细信息。查找 remote 标签,该标签表示远程执行的操作、linux-sandbox 在本地沙盒内执行的操作,以及用于其他执行策略的其他值。操作来自远程缓存的操作会显示为 remote cache hit。

例如:

INFO: 11 processes: 6 remote cache hit, 3 internal, 2 remote.

在此示例中,有 6 次远程缓存命中,有 2 项操作没有缓存命中,且远程执行了这些命中。这 3 个内部部分可以忽略。 它通常是微小的内部操作,例如创建符号链接。此摘要不包含本地缓存命中。如果获得 0 个进程(或低于预期的数字),请运行 bazel clean,后跟构建/测试命令。

在docker一侧,我们可以看到输出

​可以看到cache主要是通过http put/get,并使用hash作为key来进行对应结果的查找。

我们重复几次bazel build后可以看到耗时很短,只有不到0.3秒:

INFO: Analyzed target //src/main:app (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
Target //src/main:app up-to-date:bazel-bin/src/main/app_deploy.jarbazel-bin/src/main/app_unsigned.apkbazel-bin/src/main/app.apk
INFO: Elapsed time: 0.286s, Critical Path: 0.03s
INFO: 0 processes.
INFO: Build completed successfully, 1 total action

这显然是cache的作用,我们也可以在BUILD文件中禁止cache。这实际上是对rule的tags设置(我们在以后再讲如何定义rule),我们在这里可以尝试对java_library这个rule添加tag,禁止cache。修改src/main/java/com/example/bazel/util/BUILD中的java_library属性如下:

这样bazel就不会对该BUILD的结果进行缓存,读者可以自行尝试对比,这里就不过多展示实验结果。

排查缓存命中问题

如果您没有获得预期的缓存命中率,请执行以下操作:

确保重新运行相同的构建/测试命令会生成缓存命中

1.运行您希望填充缓存的构建和/或测试。首次在特定堆栈上运行新 build 时,应该不会有任何远程缓存命中。在远程执行过程中,操作结果会存储在缓存中,后续运行结果应该会提取这些结果。

2.运行 bazel clean。此命令会清理您的本地缓存,这样一来,您便可以调查远程缓存命中,而结果不会被本地缓存命中遮盖。

3.(在同一机器上)运行调查的 build 和测试。

4.请查看 INFO 行,了解缓存命中率。如果您看到除 remote cache hit 和 internal 以外的任何进程,则表明您的缓存已正确填充和访问。在这种情况下,请跳到下一部分。

5.可能的差异来源是 build 中非封闭的内容,导致操作在两次运行中接收不同的操作键。如需找到这些操作,请执行以下操作:

a.重新运行相关 build 或测试以获取执行日志:

bazel clean
bazel --optional-flags build //your:target --execution_log_binary_file=/tmp/exec1.log

b. 在两次运行之间比较执行日志。确保两个日志文件中的操作完全相同。 通过差异,您可以了解两次运行之间的变化。请更新您的 build 以消除这些差异。

如果您能够解决缓存问题,并且现在重复运行会生成所有缓存命中,请跳到下一部分。

如果您的操作 ID 相同,但没有任何缓存命中,则表示配置中有某项内容阻止了缓存。继续完成此部分,检查是否存在常见问题。

如果您不需要区分执行日志,则可以改用直观易懂的 --execution_log_json_file 标志。它包含执行时间,并且不能保证顺序,因此无法用于稳定差异比较。

6.检查执行日志中的所有操作是否均将 cacheable 设置为 true。如果指定操作的执行日志中未显示 cacheable,则表示相应规则在 BUILD 文件的定义中可能有 no-cache 标记。查看执行日志中直观易懂的 progress_message 字段,以帮助确定操作的来源。

7.如果操作相同且为 cacheable 但没有缓存命中,则您的命令行中可能包含针对 build 停用缓存查询的 --noremote_accept_cached。 如果难以确定实际命令行,请使用 Build Event Protocol 中的规范命令行,如下所示: a.将 --build_event_text_file=/tmp/bep.txt 添加到 Bazel 命令中,以获取日志的文本版本。 b. 打开日志的文本版本,然后使用 command_line_label: "canonical" 搜索 structured_command_line 消息。 展开之后会列出所有选项。 c.搜索 remote_accept_cached 并检查其是否已设置为 false。 d. 如果 remote_accept_cached 为 false,请确定它位于 false 的位置:在命令行中或在 bazelrc 文件中。

确保可以跨机器进行缓存

在同一台计算机上按预期执行缓存命中后,在其他机器上运行相同的构建/测试。如果您怀疑缓存未在机器间运行,请执行以下操作:

1.对构建稍作修改,以避免命中现有缓存。

2.在第一台机器上运行构建:

bazel clean
bazel ... build ... --execution_log_binary_file=/tmp/exec1.log

3.在第二台机器上运行 build,确保包含第 1 步中所做的修改:

bazel clean
bazel ... build ... --execution_log_binary_file=/tmp/exec1.log
4.比较两次运行的执行日志。如果日志不相同,请调查构建配置是否存在差异,以及主机环境中是否存在泄露到任一 build 中的属性。

比较执行日志

执行日志包含构建期间执行的所有操作的记录。每个操作都有一个 SpawnExec 元素,其中包含操作键中的所有信息。因此,如果日志相同,则操作缓存键也相同。

如需比较两个未按预期共享缓存命中的构建的日志,请执行以下操作:

1.从每个 build 中获取执行日志,并将其存储为 /tmp/exec1.log 和 /tmp/exec2.log。

2. 下载 Bazel 源代码,然后使用以下命令导航到 Bazel 文件夹。您需要使用源代码来使用 execlog 解析器解析执行日志。

git clone https://github.com/bazelbuild/bazel.git
cd bazel

3.使用执行日志解析器将日志转换为文本。以下调用还会对第二个日志中的操作进行排序,以匹配第一个日志中的操作顺序,以方便比较。

bazel build src/tools/execlog:parser
bazel-bin/src/tools/execlog/parser \--log_path=/tmp/exec1.log \--log_path=/tmp/exec2.log \--output_path=/tmp/exec1.log.txt \--output_path=/tmp/exec2.log.txt

4.使用您最喜欢的文本,差异为 /tmp/exec1.log.txt 和 /tmp/exec2.log.txt。

实际上,remote caching只是最基本的一个结果缓存机制,部署和使用都很简单,这里也只是对此进行快捷说明。小团队完全可以用这种方式来部分提升效率。而远程执行(Remote Execution)往往集成了缓存功能,因此在实际大型团队部署中一般不会专门对Remote Cache创建server。我们在下一节来介绍Remote Execution.

本文属于如下文章中的子章节

bazel学习系列章节汇总_m0_74043383的博客-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/117385.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

开启EMQX的SSL模式及SSL证书生成流程

生成证书 首先:需要安装Openssl 以下是openssl命令 生成CA证书 1.openssl genrsa -out rootCA.key 2048 2.openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 3650 -subj "/CCN/STShandong/Ljinan/Oyunding/OUplatform/CNrootCA" -out ro…

unity 发布apk,在应用内下载安装apk(用于更大大版本)

*注意事项: 1,andriod 7.0 和 android 8.0是安卓系统的分水岭,需要分开来去实现相关内容2,注意自己的包名,在设置一些共享文件的时候需要放自己的包名3,以下是直接用arr包放入unity中直接使用的,不需要导入…

尚硅谷SpringMVC (5-8)

五、域对象共享数据 1、使用ServletAPI向request域对象共享数据 首页&#xff1a; Controller public class TestController {RequestMapping("/")public String index(){return "index";} } <!DOCTYPE html> <html lang"en" xmln…

安达发|APS软件排程规则及异常处理方案详解

随着科技的发展&#xff0c;工业生产逐渐向智能化、自动化方向发展。APS(高级计划与排程)软件作为一种集成了先进技术和理念的工业软件&#xff0c;可以帮助企业实现生产过程的优化和控制。其中&#xff0c;排程规则是APS软件的核心功能之一&#xff0c;它可以帮助企业合理安排…

时序预测 | MATLAB实现CNN-BiGRU卷积双向门控循环单元时间序列预测

时序预测 | MATLAB实现CNN-BiGRU卷积双向门控循环单元时间序列预测 目录 时序预测 | MATLAB实现CNN-BiGRU卷积双向门控循环单元时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.MATLAB实现CNN-BiGRU卷积双向门控循环单元时间序列预测&#xff1b; 2.运行环境…

Docker技术--Docker简介和架构

1.Docker简介 (1).引入 我们之前学习了EXSI&#xff0c;对于虚拟化技术有所了解&#xff0c;但是我们发现类似于EXSI这样比较传统的虚拟化技术是存在着一定的缺陷:所占用的资源比较多&#xff0c;简单的说&#xff0c;就是你需要给每一个用户提供一个操作平台&#xff0c;这一个…

一款windows的终端神奇,类似mac的iTem2

终于找到了一款windows的终端神奇。类似mac的iTem2 来&#xff0c;上神器 cmder cmder是一款windows的命令行工具&#xff0c;就是我们的linux的终端&#xff0c;用起来和linux的命令一样。所以我们今天要做的是安装并配置cmder ![在这里插入图片描述](https://img-blog.csdni…

Lnmp架构-Redis

网站&#xff1a;www.redis.cn redis 部署 make的时候需要gcc和make 如果在纯净的环境下需要执行此命令 [rootserver3 redis-6.2.4]# yum install make gcc -y 注释一下这几行 vim /etc/redis/6739.conf 2.Redis主从复制 设置 11 是master 12 13 是slave 在12 上 其他节…

python 深度学习 解决遇到的报错问题4

目录 一、DLL load failed while importing _imaging: 找不到指定的模块 二、Cartopy安装失败 三、simplejson.errors.JSONDecodeError: Expecting value: line 1 column 1 (char 0) 四、raise IndexError("single positional indexer is out-of-bounds") 五、T…

QT Creator工具介绍及使用

一、QT的基本概念 QT主要用于图形化界面的开发&#xff0c; QT是基于C编写的一套界面相关的类库&#xff0c;如进程线程库&#xff0c;网络编程的库&#xff0c;数据库操作的库&#xff0c;文件操作的库等。 如何使用这个类库&#xff1a;类库实例化对象(构造函数) --> 学习…

简单了解ICMP协议

目录 一、什么是ICMP协议&#xff1f; 二、ICMP如何工作&#xff1f; 三、ICMP报文格式 四、ICMP的作用 五、ICMP的典型应用 5.1 Ping程序 5.2 Tracert(Traceroute)路径追踪程序 一、什么是ICMP协议&#xff1f; ICMP因特网控制报文协议是一个差错报告机制&#xff0c;…

【【萌新的STM32学习-18 中断的基本概念3】】

萌新的STM32学习-18 中断的基本概念3 EXTI和IO映射的关系 AFIO简介&#xff08;F1&#xff09; Alternate Function IO 复用功能IO 主要用于重映射和外部中断映射配置 1.调试IO配置 来自AFIO_MAPR[26:24] , 配置JTAG/SWD的开关状态 &#xff08;这个我们并不用太过深刻的关注&…

腾讯云网站备案详细流程_审核时间说明

腾讯云网站备案流程先填写基础信息、主体信息和网站信息&#xff0c;然后提交备案后等待腾讯云初审&#xff0c;初审通过后进行短信核验&#xff0c;最后等待各省管局审核&#xff0c;前面腾讯云初审时间1到2天左右&#xff0c;最长时间是等待管局审核时间&#xff0c;网站备案…

【易售小程序项目】修改“我的”界面前端实现;查看、重新编辑、下架自己发布的商品【后端基于若依管理系统开发】

文章目录 “我的”界面修改效果界面实现界面整体代码 查看已发布商品界面效果商品数据表后端上架、下架商品ControllerMapper 界面整体代码back方法 编辑商品、商品发布、保存草稿后端商品校验方法Controller 页面整体代码 “我的”界面修改 效果 界面实现 界面的实现使用了一…

DevOps理念:开发与运维的融合

在现代软件开发领域&#xff0c;DevOps 不仅仅是一个流行的词汇&#xff0c;更是一种文化、一种哲学和一种方法论。DevOps 的核心理念是通过开发和运维之间的紧密合作&#xff0c;实现快速交付、高质量和持续创新。本文将深入探讨 DevOps 文化的重要性、原则以及如何在团队中实…

Python入门教程 - 基本语法 (一)

目录 一、注释 二、Python的六种数据类型 三、字符串、数字 控制台输出练习 四、变量及基本运算 五、type()语句查看数据的类型 六、字符串的3种不同定义方式 七、数据类型之间的转换 八、标识符命名规则规范 九、算数运算符 十、赋值运算符 十一、字符串扩展 11.1…

Ubuntu20.04下安装搜狗输入法Linux版

Ubuntu20.04下安装搜狗输入法Linux版 参考搜狗输入法的官网安装指南&#xff1b; 第一步&#xff1a;打开搜狗输入法官网&#xff1b; https://shurufa.sogou.com/ 点击X86_64后将会自动跳转到搜狗输入法的安装指南中&#xff1b; 安装指南 Ubuntu搜狗输入法安装指南 搜狗…

iOS开发Swift-7-得分,问题序号,约束对象,提示框,类方法与静态方法-趣味问答App

1.根据用户回答计算得分 ViewController.swift: import UIKitclass ViewController: UIViewController {var questionIndex 0var score 0IBOutlet weak var questionLabel: UILabel!IBOutlet weak var scoreLabel: UILabel!override func viewDidLoad() {super.viewDidLoad()…

如何停止一个正在运行的线程

使用共享变量的方式 在这种方式中&#xff0c;之所以引入共享变量&#xff0c;是因为该变量可以被多个执行相同任务的线程用来作为是否中断的信号&#xff0c;通知中断线程的执行。 使用interrupt方法终止线程 如果一个线程由于等待某些事件的发生而被阻塞&#xff0c;又该怎样…

Vavido IP核Independent Clocks Block RAM FIFO简述

文章目录 1 FIFO&#xff08;先入先出&#xff09;1.1 概念1.2 应用场景1.3 FIFO信号1.4 FIFO读写时序1.4.1 FIFO读时序1.4.2 FIFO写时序 参考 1 FIFO&#xff08;先入先出&#xff09; 1.1 概念 FIFO&#xff08;First in First out&#xff09;即先入先出队列&#xff0c;是…