動態執行是 Bazel 的一項功能,可平行啟動相同動作的本機和遠端執行作業,並使用第一個完成的分支機構輸出內容,取消其他分支機構。這項功能結合了遠端建構系統的執行能力和/或大型共用快取,以及本機執行的低延遲時間,為乾淨和累加建構作業提供兩全其美的解決方案。
本頁說明如何啟用、調整及偵錯動態執行。如果您已設定本機和遠端執行,並嘗試調整 Bazel 設定以提升效能,這份頁面就適合您。如果尚未設定遠端執行,請先參閱 Bazel 遠端執行總覽。
是否啟用動態執行?
動態執行模組是 Bazel 的一部分,但如要使用動態執行,您必須已能從相同的 Bazel 設定在本機和遠端進行編譯。
如要啟用動態執行模組,請將 --internal_spawn_scheduler
標記傳遞至 Bazel。這會新增名為 dynamic
的執行策略。現在,您可以將這項功能做為動態放送的記憶符號策略,例如 --strategy=Javac=dynamic
。如要瞭解如何選擇啟用動態執行的助記符,請參閱下一節。
如果是使用動態策略的任何助記符,遠端執行策略會取自 --dynamic_remote_strategy
旗標,本機策略則取自 --dynamic_local_strategy
旗標。傳遞 --dynamic_local_strategy=worker,sandboxed
會將動態執行的本機分支預設為依序嘗試使用工作站或沙箱執行。傳遞 --dynamic_local_strategy=Javac=worker
只會覆寫 Javac 助記符的預設值。遠端版本也是如此。這兩個標記都可以多次指定。如果動作無法在本機執行,系統會照常遠端執行,反之亦然。
如果遠端系統有快取,--dynamic_local_execution_delay
旗標會在遠端系統指出快取命中後,將延遲時間 (以毫秒為單位) 新增至本機執行作業。這樣一來,當快取命中次數較多時,就不會執行本機執行作業。預設值為 1000 毫秒,但應調整為比快取命中通常所需時間稍長。實際時間取決於遠端系統和往返時間。通常,特定遠端系統的所有使用者值都會相同,除非部分使用者距離夠遠,導致來回延遲。您可以使用 Bazel 剖析功能,查看一般快取命中時間。
動態執行可搭配本機沙箱策略和持續性工作人員使用。搭配動態執行作業使用時,持續性工作人員會自動透過沙箱執行,且無法使用多工工作人員。在 Darwin 和 Windows 系統上,沙箱策略可能會很慢;您可以傳遞 --reuse_sandbox_directories
,減少在這些系統上建立沙箱的負擔。
動態執行也可以搭配 standalone
策略執行,但由於 standalone
策略必須在開始執行時取得輸出鎖定,因此會有效阻止遠端策略先完成。--experimental_local_lockfree_output
旗標可讓本機執行作業直接寫入輸出內容,但如果遠端執行作業先完成,就會中止本機執行作業,藉此解決這個問題。
如果動態執行的其中一個分支先完成,但失敗了,整個動作就會失敗。這是刻意選擇,可避免本地和遠端執行之間的差異遭到忽略。
如要進一步瞭解動態執行和鎖定機制,請參閱 Julio Merino 的網誌文章
何時該使用動態執行?
動態執行需要某種形式的遠端執行系統。 目前無法使用僅限快取的遠端系統,因為快取未命中會視為動作失敗。
並非所有類型的動作都適合遠端執行。最適合的候選項目是本質上在本機執行速度較快的項目 (例如使用持續性工作站),或是執行速度夠快,以致於遠端執行作業的負擔會佔據執行時間的項目。由於每個在本機執行的動作都會鎖定一定數量的 CPU 和記憶體資源,因此執行不屬於這些類別的動作只會延遲屬於這些類別的動作執行。
自版本 5.0.0-pre.20210708.4 起,效能剖析會包含有關工作人員執行的資料,包括在動態執行競爭中落敗後,完成工作要求所花費的時間。如果發現動態執行工作站執行緒花費大量時間取得資源,或花費大量時間在 async-worker-finish
中,可能表示有些緩慢的本機動作會延遲工作站執行緒。
在上述使用 8 個 Javac 工作站的設定檔中,我們看到許多 Javac 工作站輸掉競爭,並在 async-worker-finish
執行緒上完成工作。這是因為非工作站助記符占用的資源足夠,導致工作站延遲。
如果只使用動態執行功能執行 Javac,開始工作後,只有大約一半的工作站會輸掉競賽。
先前建議使用的 --experimental_spawn_scheduler
旗標已淘汰。這會啟用動態執行,並將 dynamic
設為所有助記符的預設策略,這通常會導致這類問題。
成效
動態執行方法會假設本機和遠端有足夠的可用資源,因此值得花費一些額外資源來提升整體效能。但過度使用資源可能會導致 Bazel 本身或執行 Bazel 的機器變慢,或對遠端系統造成意想不到的壓力。您可以透過下列幾種方式變更動態執行的行為:
如果目前建構期間發生遠端快取命中,--dynamic_local_execution_delay
會在遠端分支啟動後,延遲啟動本機分支,延遲時間為數毫秒。這樣一來,當大部分輸出內容都可能位於快取中時,可從遠端快取獲益的建構作業就不會浪費本機資源。視快取品質而定,減少這項設定可能會提高建構速度,但代價是會使用更多本機資源。
--experimental_dynamic_local_load_factor
是實驗性的進階資源管理選項。值介於 0 到 1 之間,0 代表關閉這項功能。
如果設為大於 0 的值,當有許多動作等待排程時,Bazel 會調整本機排程動作的數量。如果設為 1,系統會排定與可用 CPU 數量 (如 --local_cpu_resources
所述) 相同數量的動作。如果設為較低的值,系統排定的動作數量會相應減少,因為可執行的動作數量較多。這聽起來可能違反直覺,但如果遠端系統良好,在執行許多動作時,本機執行並無太大幫助,本機 CPU 最好用於管理遠端動作。
--experimental_dynamic_slow_remote_time
會優先啟動本機分支版本,前提是遠端分支版本已執行至少這麼久的時間。通常最近排定的動作會優先執行,因為最有可能勝出,但如果遠端系統有時會停止運作或耗時過長,這項功能就能讓建構作業繼續進行。這項功能預設為停用,因為可能會隱藏應修正的遠端系統問題。啟用這個選項後,請務必監控遠端系統效能。
--experimental_dynamic_ignore_local_signals
可用於在特定信號導致本機衍生項目結束時,讓遠端分支接管。這項功能主要與工作站資源限制搭配使用 (請參閱 --experimental_worker_memory_limit_mb
、--experimental_worker_sandbox_hardening
和 --experimental_sandbox_memory_limit_mb
),工作站程序可能會在資源用量過多時遭到終止。
JSON 追蹤設定檔包含多個與效能相關的圖表,可協助您找出改善效能和資源用量之間取捨的方法。
疑難排解
動態執行的問題可能很細微,難以偵錯,因為這些問題可能只會在特定本機和遠端執行組合中顯現。--debug_spawn_scheduler
會從動態執行系統新增額外輸出內容,有助於偵錯這些問題。您也可以調整 --dynamic_local_execution_delay
旗標和遠端與本機工作數量,以便重現問題。
如果使用 standalone
策略時動態執行發生問題,請嘗試不使用 --experimental_local_lockfree_output
執行,或在沙箱中執行本機動作。這可能會稍微減緩建構速度 (如果您使用 Mac 或 Windows,請參閱上文),但可排除一些可能導致失敗的原因。