Bazel Remote Cache 緩存問題
簡介
公司 iOS 項(xiàng)目使用 bazel
使用編譯,同時 bazel
支持遠(yuǎn)程緩存。 使用遠(yuǎn)程緩存,可以加速編譯速度,節(jié)省編譯時間。
緩存服務(wù)器很簡單,支持 GET、 PUT 操作,分別為獲取和上傳,官網(wǎng)有說明 Bazel Remote Cache。
build --remote_cache=http://mycache.com
但是在 CI 服務(wù)器上,偶爾會出現(xiàn)連接出現(xiàn)異常問題,如連接重置、斷開、超時、dns無法解析等。大概有5%的概率。分析 bazel 源碼,發(fā)現(xiàn) bazel 底層使用 netty 進(jìn)行http通信。遠(yuǎn)程服務(wù)器日志也沒有發(fā)現(xiàn)問題。
和常規(guī)解決思路不一樣,bazel 運(yùn)行的時候無法進(jìn)行抓包,因?yàn)槭歉怕市缘模⑶?CI 機(jī)器有多臺,無法統(tǒng)一進(jìn)行排查。
解決
從錯誤信息來看,可能是因?yàn)?CPU 使用率過高,導(dǎo)致影響網(wǎng)絡(luò)請求,出現(xiàn)連接超時、斷開、重置、dns無法解析等。
調(diào)優(yōu)連接
# 降低連接數(shù),默認(rèn)為100
--remote_max_connections=10
# 增加超時時長,默認(rèn)為60s
--remote_timeout=100s
調(diào)優(yōu)CPU
# 降低CPU與線程數(shù)
--loading_phase_threads=HOST_CPUS*.9
使用本地緩存降低請求量
bazel 自己是支持本地緩存的,并且同時支持本地和遠(yuǎn)程。但是不夠智能,不能及時清理老的緩存文件,同時本地和遠(yuǎn)程是串行的。如上傳,先寫本地,再上傳。還是無法降低網(wǎng)絡(luò)請求的數(shù)量。
可參考官方源碼 DiskAndRemoteCacheClient.java
結(jié)合微服務(wù)中的 SideCar 和 cdn 思路,可以在本地啟動一個緩存服務(wù)。
上傳的時候,直接先把緩存放在磁盤中,同時再異步上傳到遠(yuǎn)程,同時控制異步上傳的數(shù)據(jù)量,類似有個MQ進(jìn)行異步處理,進(jìn)行消峰操作。
下載的時候,如果本地有緩存,則直接返回。如果沒有則先下載,再進(jìn)行返回。控制下載線程數(shù),合理規(guī)避超時與異常情況。
同時 bazel 有同一個時刻多次請求相同的緩存資源的情況,使用本地緩存,可以避免這樣的問題。
build --remote_cache=http://127.0.0.1:8080/
總結(jié)
通過以上三種方式,暫時有效的解決編譯時候出現(xiàn) netty 異常問題。
第三種方式,使用本地緩存進(jìn)行代理中間也是踩過許多坑。
第一次使用Spring Boot 啟動一個服務(wù),然后再使用 okhttp 進(jìn)行遠(yuǎn)程服務(wù)的下載與上傳,確實(shí)可以降低異常出現(xiàn)的概率,但是不夠完美。
第二次換成了Spring Cloud Gateway,想采用nginx的那種方式,不過因?yàn)?Gateway 使用的是完全異步的方式,進(jìn)行緩存本地化的時候有點(diǎn)吃力,可能是自己學(xué)藝不精。
第三次又回退到第一次的方式,并進(jìn)行了一些列的優(yōu)化,但是還是有小范圍的概率。因?yàn)?Spring Boot 是基于 java 的,整個服務(wù)自己消耗有點(diǎn)高。
第四次,參照第三次的邏輯,使用go語言重新寫了一遍,本地緩存服務(wù)自己消耗的資源確實(shí)有很大程度降低,JAVA 版本最高的時候,自己需要占2G內(nèi)存,使用go版本最高時候只要100M,差距很明顯。
第五次,按理說第四次方案已經(jīng)很完美,但是還是有小概率的出現(xiàn),通過查找資料。bazel 自己是支持代理的,但是不是普通的http與socks5 代理,是 unix domain socket。
結(jié)合第四種,把go的http版本改成 go的 unix domain socket的即可,修改成本比較低。已上線使用,目前效果良好
# 走自己的代理,代理會進(jìn)行磁盤緩存。
build --remote_proxy=unix:/tmp/bazel-car-go-unix.socket
以上就是自己排查 bazel 打包問題的歷程。經(jīng)歷3個月,收獲頗多,尤其是go語言在網(wǎng)絡(luò)方面的使用,設(shè)計(jì)真的是太好了。