動態執行

回報問題 查看原始碼 Nightly · 8.0 . 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

動態執行是 Bazel 的一項功能,可同時啟動相同動作的本機和遠端執行作業,並使用第一個完成分支的輸出內容,取消其他分支。它結合了遠端建構系統的執行效能和/或大型共用快取,以及本機執行作業的低延遲時間,為清除和增量建構作業提供兩者兼具的最佳效能。

本頁說明如何啟用、調整及偵錯動態執行作業。如果您已設定本機和遠端執行作業,並嘗試調整 Bazel 設定以提升效能,這篇文章正是您需要的參考資料。如果您尚未設定遠端執行作業,請先參閱 Bazel 的遠端執行作業總覽

是否要啟用動態執行功能?

動態執行模組是 Bazel 的一部分,但要使用動態執行功能,您必須能夠透過相同的 Bazel 設定在本機和遠端編譯。

如要啟用動態執行模組,請將 --internal_spawn_scheduler 標記傳遞至 Bazel。這會新增名為 dynamic 的新執行策略。您現在可以將這項做法用於要動態執行的助憶法,例如 --strategy=Javac=dynamic。如要瞭解如何選擇要啟用動態執行作業的助憶法,請參閱下一節。

對於使用動態策略的任何助憶法,系統會從 --dynamic_remote_strategy 旗標取得遠端執行策略,從 --dynamic_local_strategy 旗標取得本機策略。傳遞 --dynamic_local_strategy=worker,sandboxed 會為動態執行的本機分支設定預設值,以便依序嘗試使用 worker 或沙箱執行。傳遞 --dynamic_local_strategy=Javac=worker 只會覆寫 Javac 助憶法的預設值。遠端版本的運作方式也相同。兩個標記皆可多次指定。如果無法在本機執行動作,系統會正常執行遠端動作,反之亦然。

如果遠端系統有快取,--dynamic_local_execution_delay 標記會在遠端系統指出快取命中後,為本機執行作業增加毫秒的延遲時間。這樣一來,當快取命中次數增加時,就不會執行本機執行作業。預設值為 1000 毫秒,但應調整為比快取命中通常所需時間稍長一點。實際時間取決於遠端系統和往返所需時間。通常,特定遠端系統的所有使用者都會使用相同的值,除非其中部分使用者距離太遠,導致往返延遲時間增加。您可以使用 Bazel 分析功能查看快取命中通常需要多久的時間。

動態執行功能可搭配本機沙箱策略和持續性工作者使用。當持久性 worker 與動態執行作業搭配使用時,系統會自動以沙箱模式執行,且無法使用multiplex worker。在 Darwin 和 Windows 系統上,沙箱策略可能會變慢;您可以傳遞 --reuse_sandbox_directories,以減少在這些系統上建立沙箱的額外負擔。

動態執行作業也可以搭配 standalone 策略執行,但由於 standalone 策略必須在開始執行時取得輸出鎖定,因此實際上會阻止遠端策略先行完成。--experimental_local_lockfree_output 標記可解決這個問題,方法是允許本機執行作業直接寫入輸出內容,但如果遠端執行作業先完成,則會中斷本機執行作業。

如果動態執行的其中一個分支先完成但失敗,整個動作就會失敗。這是有意選擇的做法,可避免本地和遠端執行作業之間的差異遭到忽略。

如要進一步瞭解動態執行作業及其鎖定機制,請參閱 Julio Merino 的優質網誌文章

何時該使用動態執行?

動態執行作業需要某種形式的遠端執行系統。目前無法使用僅快取的遠端系統,因為快取未命中會視為失敗的動作。

並非所有類型的動作都適合遠端執行。最理想的候選項目是本機本身速度較快的項目,例如使用持續性工作站,或是執行速度夠快,遠端執行作業的額外負擔會影響執行時間的項目。由於每個本機執行的動作都會鎖定一定數量的 CPU 和記憶體資源,因此執行不屬於這些類別的動作,只會延遲執行屬於這些類別的動作。

5.0.0-pre.20210708.4 版本起,效能分析剖析就會包含有關 worker 執行作業的資料,包括在輸掉動態執行競爭後,完成工作要求所花費的時間。如果您發現動態執行工作站執行緒花費大量時間取得資源,或是在 async-worker-finish 中花費大量時間,表示您可能有某些緩慢的本機動作會延遲工作站執行緒。

分析動態執行效能不佳的資料

在上述使用 8 個 Javac 工作站的設定檔中,我們發現許多 Javac 工作站輸掉了競爭,並在 async-worker-finish 執行緒上完成工作。這是因為非 worker 助憶法占用足夠的資源,導致 worker 延遲。

剖析資料,提升動態執行效能

當只有 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 可用於讓遠端分支在本機產生的子程序因特定信號而結束時接管。這項功能主要可與 worker 資源限制搭配使用 (請參閱 --experimental_worker_memory_limit_mb--experimental_worker_sandbox_hardening--experimental_sandbox_memory_limit_mb)),當 worker 程序使用過多資源時,可能會遭到終止。

JSON 追蹤記錄設定檔包含多個效能相關圖表,可協助您找出改善效能和資源使用率的權衡做法。

疑難排解

動態執行的問題可能很難偵測,因為只有在本機和遠端執行的特定組合下才會出現。--debug_spawn_scheduler 會從動態執行系統中新增額外輸出內容,協助您對這些問題進行偵錯。您也可以調整 --dynamic_local_execution_delay 標記和遠端工作與本機工作的數量,以便更輕鬆地重現問題。

如果您在使用 standalone 策略執行動態動作時遇到問題,請嘗試在不使用 --experimental_local_lockfree_output 的情況下執行,或是在沙箱中執行本機動作。這可能會稍微減緩建構作業 (如果您使用 Mac 或 Windows,請參閱上述說明),但可排除部分可能導致失敗的原因。