Bazel Remote Cache 緩存問題 Bazel Remote Cache 緩存問題

Bazel Remote Cache 緩存問題


簡介

公司 iOS 項目使用 bazel 使用編譯,同時 bazel 支持遠程緩存。 使用遠程緩存,可以加速編譯速度,節省編譯時間。

緩存服務器很簡單,支持 GET、 PUT 操作,分別爲獲取和上傳,官網有說明 Bazel Remote Cache

build --remote_cache=http://mycache.com

但是在 CI 服務器上,偶爾會出現連接出現異常問題,如連接重置、斷開、超時、dns無法解析等。大概有5%的概率。分析 bazel 源碼,發現 bazel 底層使用 netty 進行http通信。遠程服務器日誌也沒有發現問題。
和常規解決思路不一樣,bazel 運行的時候無法進行抓包,因爲是概率性的,並且 CI 機器有多臺,無法統一進行排查。

解決

從錯誤信息來看,可能是因爲 CPU 使用率過高,導致影響網絡請求,出現連接超時、斷開、重置、dns無法解析等。

調優連接

# 降低連接數,默認爲100
--remote_max_connections=10 

# 增加超時時長,默認爲60s
--remote_timeout=100s

調優CPU

參數文檔

# 降低CPU與線程數
--loading_phase_threads=HOST_CPUS*.9

使用本地緩存降低請求量

bazel 自己是支持本地緩存的,並且同時支持本地和遠程。但是不夠智能,不能及時清理老的緩存文件,同時本地和遠程是串行的。如上傳,先寫本地,再上傳。還是無法降低網絡請求的數量。

可參考官方源碼 DiskAndRemoteCacheClient.java

結合微服務中的 SideCar 和 cdn 思路,可以在本地啓動一個緩存服務。

上傳的時候,直接先把緩存放在磁盤中,同時再異步上傳到遠程,同時控制異步上傳的數據量,類似有個MQ進行異步處理,進行消峯操作。

下載的時候,如果本地有緩存,則直接返回。如果沒有則先下載,再進行返回。控制下載線程數,合理規避超時與異常情況。
同時 bazel 有同一個時刻多次請求相同的緩存資源的情況,使用本地緩存,可以避免這樣的問題。

build --remote_cache=http://127.0.0.1:8080/

總結

通過以上三種方式,暫時有效的解決編譯時候出現 netty 異常問題。

第三種方式,使用本地緩存進行代理中間也是踩過許多坑。

第一次使用Spring Boot 啓動一個服務,然後再使用 okhttp 進行遠程服務的下載與上傳,確實可以降低異常出現的概率,但是不夠完美。

第二次換成了Spring Cloud Gateway,想採用nginx的那種方式,不過因爲 Gateway 使用的是完全異步的方式,進行緩存本地化的時候有點喫力,可能是自己學藝不精。

第三次又回退到第一次的方式,並進行了一些列的優化,但是還是有小範圍的概率。因爲 Spring Boot 是基於 java 的,整個服務自己消耗有點高。

第四次,參照第三次的邏輯,使用go語言重新寫了一遍,本地緩存服務自己消耗的資源確實有很大程度降低,JAVA 版本最高的時候,自己需要佔2G內存,使用go版本最高時候只要100M,差距很明顯。

第五次,按理說第四次方案已經很完美,但是還是有小概率的出現,通過查找資料。bazel 自己是支持代理的,但是不是普通的http與socks5 代理,是 unix domain socket。
結合第四種,把go的http版本改成 go的 unix domain socket的即可,修改成本比較低。已上線使用,目前效果良好

Bazel Remote Proxy

# 走自己的代理,代理會進行磁盤緩存。
build --remote_proxy=unix:/tmp/bazel-car-go-unix.socket

以上就是自己排查 bazel 打包問題的歷程。經歷3個月,收穫頗多,尤其是go語言在網絡方面的使用,設計真的是太好了。

相關資料

Bazel

Bazel Remote Cache

Bazel Remote Proxy

Bazel Github

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章