遠端快取

回報問題 查看來源 Nightly · 8.4 · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

本頁涵蓋遠端快取、設定伺服器來代管快取,以及使用遠端快取執行建構作業。

開發人員團隊和/或持續整合 (CI) 系統會使用遠端快取,共用建構輸出內容。如果建構作業可重現,則可安全地在另一部機器上重複使用某部機器的輸出內容,大幅加快建構作業速度。

總覽

Bazel 會將建構作業細分成個別步驟,也就是動作。每個動作都有輸入內容、輸出名稱、指令列和環境變數。每個動作都會明確宣告必要輸入和預期輸出。

您可以將伺服器設為建構輸出內容的遠端快取,也就是這些動作輸出內容。這些輸出內容包含輸出檔案名稱清單,以及內容的雜湊值。有了遠端快取,您就能重複使用另一位使用者的建構作業輸出內容,不必在本機建構每個新的輸出內容。

如要使用遠端快取,請按照下列步驟操作:

  • 將伺服器設為快取的後端
  • 設定 Bazel 建構作業,以便使用遠端快取
  • 使用 Bazel 0.10.0 以上版本

遠端快取會儲存兩種資料:

  • 動作快取,這是動作雜湊到動作結果中繼資料的對應。
  • 輸出檔案的內容可定址儲存庫 (CAS)。

請注意,遠端快取也會儲存每個動作的 stdout 和 stderr。因此,檢查 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 是開放原始碼的網路伺服器。透過 [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 是開放原始碼的遠端建構快取,可在基礎架構上使用。自 2018 年初以來,多間公司已在實際工作環境中成功使用這項技術。請注意,Bazel 專案不提供 bazel-remote 的技術支援。

這個快取會將內容儲存在磁碟上,並提供垃圾收集功能,以強制執行儲存空間上限和清除未使用的構件。快取可做為 [Docker 映像檔],程式碼則可在 GitHub 上取得。 REST 和 gRPC 遠端快取 API 皆支援。

如需使用說明,請參閱 GitHub 頁面。

Google Cloud Storage

[Google Cloud Storage] 是全代管物件儲存庫,提供與 Bazel 遠端快取通訊協定相容的 HTTP API。您必須擁有已啟用計費功能的 Google Cloud 帳戶。

如要將 Cloud Storage 做為快取,請按照下列步驟操作:

  1. 建立儲存空間 bucket。 請務必選取最靠近您的值區位置,因為網路頻寬對遠端快取很重要。

  2. 為 Bazel 建立服務帳戶,以便向 Cloud Storage 進行驗證。請參閱「建立服務帳戶」。

  3. 產生私密 JSON 金鑰,然後傳送至 Bazel 進行驗證。請妥善保存金鑰,因為擁有金鑰的任何人都能從 GCS 值區讀取/寫入任意資料。

  4. 在 Bazel 指令中加入下列標記,即可連線至 Cloud Storage:

    • 使用標記將下列網址傳遞至 Bazel: --remote_cache=https://storage.googleapis.com/bucket-name,其中 bucket-name 是儲存空間 bucket 的名稱。
    • 使用 --google_credentials=/path/to/your/secret-key.json 旗標傳遞驗證金鑰,或使用 --google_default_credentials 旗標來使用應用程式驗證
  5. 您可以將 Cloud Storage 設為自動刪除舊檔案。如要瞭解如何管理物件生命週期,請參閱這篇文章

其他伺服器

您可以設定任何支援 PUT 和 GET 的 HTTP/1.1 伺服器做為快取的後端。據使用者回報,HazelcastApache httpdAWS S3 等快取後端都可成功運作。

驗證

從 0.11.0 版開始,Bazel 新增了對 HTTP 基本驗證的支援。 您可以透過遠端快取網址,將使用者名稱和密碼傳遞至 Bazel。語法為 https://username:password@hostname.com:port/path。請注意,HTTP 基本驗證會透過網路以純文字傳輸使用者名稱和密碼,因此務必搭配 HTTPS 使用。

HTTP 快取通訊協定

Bazel 支援透過 HTTP/1.1 進行遠端快取。這個通訊協定在概念上很簡單: 二進位資料 (BLOB) 會透過 PUT 要求上傳,並透過 GET 要求下載。 動作結果中繼資料會儲存在 /ac/ 路徑下,輸出檔案則會儲存在 /cas/ 路徑下。

舉例來說,假設遠端快取在 http://localhost:8080/cache 下執行。如要下載 SHA256 雜湊為 01ba4719... 的動作,Bazel 要求如下:

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

如要將 SHA256 雜湊 15e2b0d3... 的輸出檔案上傳至 CAS,Bazel 要求如下:

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

0x310x320x330x340x350x360x370x380x39

使用遠端快取執行 Bazel

將伺服器設為遠端快取後,如要使用遠端快取,必須在 Bazel 指令中新增標記。請參閱下方的設定清單和對應旗標。

您可能也需要設定驗證,這取決於您選擇的伺服器。

您可以在 .bazelrc 檔案中新增這些標記,這樣就不必每次執行 Bazel 時都指定這些標記。視專案和團隊動態而定,您可以將旗標新增至下列 .bazelrc 檔案:

  • 在本機電腦上
  • 在專案的工作區中,與團隊共用
  • 在 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"],
)

從遠端快取中刪除內容

從遠端快取刪除內容是管理伺服器的一環。 從遠端快取刪除內容的方式,取決於您設定為快取的伺服器。刪除輸出內容時,可以刪除整個快取, 也可以刪除舊的輸出內容。

快取輸出內容會儲存為一組名稱和雜湊值。刪除內容時,無法區分輸出內容屬於哪個特定建構版本。

您可能會基於下列原因刪除快取中的內容:

  • 在快取中毒後建立乾淨的快取
  • 刪除舊輸出內容,減少使用的儲存空間

Unix 通訊端

遠端 HTTP 快取支援透過 Unix 網域通訊端連線。這個行為類似於 curl 的 --unix-socket 標記。請使用下列項目設定 Unix 網域通訊端:

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

Windows 不支援這項功能。

磁碟快取

Bazel 可以使用檔案系統中的目錄做為遠端快取。切換分支版本和/或處理同一專案的多個工作區 (例如多個簽出) 時,這項功能有助於共用建構構件。請按照下列步驟啟用磁碟快取:

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

您可以使用 ~ 別名,將使用者專屬路徑傳遞至 --disk_cache 旗標 (Bazel 會替換目前使用者的主目錄)。透過專案的已簽入 .bazelrc 檔案,為專案的所有開發人員啟用磁碟快取時,這項功能就派得上用場。

垃圾收集

從 Bazel 7.4 開始,您可以使用 --experimental_disk_cache_gc_max_size--experimental_disk_cache_gc_max_age,為磁碟快取或個別快取項目的存在時間設定大小上限。Bazel 會在建構作業之間的閒置時間自動進行垃圾收集,清除磁碟快取;閒置計時器可使用 --experimental_disk_cache_gc_idle_delay 設定 (預設為 5 分鐘)。

除了自動垃圾收集功能,我們也提供工具,可視需要執行垃圾收集作業。

已知問題

在建構期間修改輸入檔案

如果在建構期間修改輸入檔案,Bazel 可能會將無效結果上傳至遠端快取。您可以使用 --experimental_guard_against_concurrent_changes 旗標啟用變更偵測功能。目前沒有已知問題,日後推出的版本將預設啟用這項功能。如需最新消息,請參閱 [問題 #3360]。一般來說,請避免在建構期間修改來源檔案。

環境變數洩漏到動作中

動作定義包含環境變數。這可能會導致機器之間無法共用遠端快取命中。舉例來說,如果環境的 $PATH 變數不同,就不會共用快取命中。動作定義只會包含透過 --action_env 明確加入許可清單的環境變數。Bazel 的 Debian/Ubuntu 套件過去會安裝 /etc/bazel.bazelrc,並使用環境變數白名單,包括 $PATH。如果快取命中次數低於預期,請檢查環境中是否有舊版 /etc/bazel.bazelrc 檔案。

Bazel 不會追蹤工作區以外的工具

Bazel 目前不會追蹤工作區以外的工具。舉例來說,如果動作使用 /usr/bin/ 的編譯器,就可能會發生問題。接著,安裝不同編譯器的兩位使用者會錯誤地共用快取命中,因為輸出內容不同,但動作雜湊相同。如需最新消息,請參閱問題 #4558

在 Docker 容器中執行建構作業時,會遺失記憶體內增量狀態 即使在單一 Docker 容器中執行,Bazel 仍會使用伺服器/用戶端架構。 在伺服器端,Bazel 會維護記憶體內狀態,加快建構速度。在 Docker 容器 (例如 CI) 內執行建構作業時,記憶體內狀態會遺失,Bazel 必須重建狀態,才能使用遠端快取。