分散式版本

當您有大型程式碼集時,依附元件鏈結可能變得很深入。即使是簡單的二進位檔,也依賴數萬個建構目標。就此規模而言,要以合理的方式在單一機器上完成建構並不理想:建構系統可能無法完整預估機器硬體上的物理學基本基礎。要達成這項目標的唯一方法,就是使用支援分散式建構作業的建構系統,系統會將系統完成的工作單元分散於任意數量且可擴充的機器。假設系統已將作業系統的工作分割為數個小型單位 (本文稍後會說明),我們可以根據想要支付的費用,快速完成各種規模的建構作業。這種擴充性是定義以 Artifact 建構建構系統所做為的堅強後盾。

遠端快取

最簡單的分散式建構作業類型就是只運用遠端快取 (如圖 1 所示) 的分散式建構作業。

採用遠端快取的分散式建構作業

圖 1. 顯示遠端快取的分散式建構

所有執行建構作業的系統 (包括開發人員工作站和持續整合系統),都會共用同一個遠端快取服務。這項服務可能是短期的本機儲存系統 (例如 Redis) 或雲端服務 (例如 Google Cloud Storage)。每當使用者需要建構成果時 (無論是直接建立或做為依附元件),系統一律會先透過遠端快取進行檢查,確認該成果是否已存在。在這種情況下,使用者可以下載構件,而不必建構。如果沒有,系統會建構構件本身,然後將結果上傳至快取。也就是說,不會經常變動的低層級依附元件可以建立一次,並與其他使用者共用,而不需要由每個使用者重新建立。Google 提供的快取服務大多是由快取提供,而非從頭開始,因此大幅降低建構建構系統的費用。

為了讓遠端快取系統能正常運作,建構系統必須確保建構作業完全可重現。也就是說,任何建構目標都必須確定該目標的輸入組合,讓同一組輸入項目在任何機器上都能產生相同的輸出內容。這個方法可確保下載構件結果與建構本身的結果相同。請注意,這需要快取中的每個構件都分別輸入目標和其雜湊的雜湊,讓不同的工程師可以同時對同一個目標做出不同的修改。遠端快取會儲存所有產生的構件,並在不衝突的情況下提供適當結果。

當然,如果想充分運用遠端快取的優勢,下載構件的速度會比建構應用程式更快。有時也不一定是如此,尤其是快取伺服器離執行建構作業的機器而言更是如此。我們會仔細調整 Google 網路和建構系統,以快速分享建構結果。

遠端執行

遠端快取並非真正的分散式建構, 如果快取遺失,或者您已進行低階變更,因此需要重新建立所有內容,您仍需要在本機執行整個建構作業。真正的目標在於支援遠端執行作業,實際建構作業的建構作業可以分配到任意數量的工作站。圖 2 說明瞭遠端執行系統。

遠端執行系統

圖 2. 遠端執行系統

每部使用者機器上執行的建構工具 (使用者為人類工程師或自動化建構系統) 都會向中央建構主要執行個體傳送要求。建構作業主要執行個體會將要求拆解為元件元件,並透過可擴充的工作站集區排定執行這些動作的時間。每個工作站都會使用使用者輸入的內容執行該動作,並寫入產生的構件。這些成果會與其他執行執行動作的電腦共用,直到可以產生最終的輸出內容並傳送給使用者為止。

實作這類系統最棘手的部分,就是管理工作站、主要執行個體和使用者本機機器之間的通訊。工作站可能會依賴其他工作站產生的中繼構件,而最終的結果必須傳回使用者的本機電腦。為達成此目標,我們得按上述分散式分散式快取為基礎,讓每個工作站將結果寫入快取並讀取快取中的依附元件。主要執行個體會阻止工作站繼續作業,直到完成所有所需作業為止,這時他們便可以從快取中讀取輸入內容。系統也會快取最終產品,供本機電腦下載。請注意,我們還需要獨立的方式,匯出使用者來源樹狀結構中的本機變更,以便工作站在建構之前套用這些變更。

為使這項功能能順利運作,在先前說明的構件建構系統中,所有部分都必須整合在一起。建構環境必須完全自行宣告,以便我們在沒有人類介入的情況下啟動工作站。建構程序本身必須完全獨立,因為每個步驟可能會在不同的機器上執行。輸出必須完全確定,因此每個工作站可以信任從其他工作站接收的結果。這類保證工作非常難以使用以工作為基礎的系統,而在這樣的情況下,建構值得信賴的遠端執行系統是不可能的任務。

Google 的分散式建構作業

自 2008 年起,Google 已採用同時採用遠端快取和遠端執行功能的分散式建構系統,如圖 3 所示。

高階建構系統

圖 3. Google 的分散式建構系統

Google 的遠端快取稱為 ObjFS。當中包含一個後端,將輸出內容儲存於儲存在整個實際工作環境機器的 Bigtable 中,以及做為前端的 FUSE Daemon。FUSE Daemon 可讓工程師瀏覽建構輸出內容,就如同一般儲存於工作站的一般檔案,但僅針對少數使用者直接要求的檔案,以隨選方式下載檔案內容的 Google Ads 新帳戶重新申請驗證。隨需提供檔案內容會大幅減少網路和磁碟用量,而且相較於我們儲存在開發人員本機磁碟中的所有建構輸出內容,可讓系統建立兩倍的速度。

Google 的遠端執行系統稱為 Forge。採用 Blaze 架構的 Forge 用戶端 (又稱為 Gradle 的內部對等體) 可將每個動作的要求傳送至在 Google 資料中心內執行的工作,也就是「排程器」。Scheduler 會維護動作結果的快取,讓其他任何系統使用者已建立動作,因此可立即傳回回應。如果沒有,系統會將動作排入佇列。多個 Executor 工作集區會持續讀取這個佇列的動作、執行並執行結果,並將結果直接儲存在 ObjFS Bigtable 中。執行者可以取得這些結果,以供日後執行動作之用,也可以由 objfsd 下載。

最終結果是可擴充的系統,可以有效支援在 Google 中執行的所有建構作業。Google 的建構作業規模極大,Google 會執行數百萬個建構作業,無論是執行數十億個測試案例,或是每天產生數十億次的原始碼輸出內容,都能產生 PB 規模的建構輸出內容。這類系統不僅讓我們的工程師能快速建構複雜的程式碼集,也方便我們實作大量自動化工具和系統,來建構應用程式。