背景
云原生下的流水線(xiàn)是通過(guò)啟動(dòng)容器來(lái)運(yùn)行具體的功能步驟,每次運(yùn)行流水線(xiàn)可能會(huì)被調(diào)度到不同的計(jì)算節(jié)點(diǎn)上。這會(huì)導(dǎo)致一個(gè)問(wèn)題:容器運(yùn)行完是不會(huì)保存數(shù)據(jù)的,每當(dāng)流水線(xiàn)重新運(yùn)行時(shí),又會(huì)重新拉取代碼、編譯代碼、下載依賴(lài)包等等。在云原生場(chǎng)景下,不存在本地宿主機(jī)編譯代碼、構(gòu)建鏡像時(shí)緩存的作用,大大延長(zhǎng)了流水線(xiàn)運(yùn)行時(shí)間,浪費(fèi)很多不必要的時(shí)間、網(wǎng)絡(luò)和計(jì)算成本。在許多流水線(xiàn)場(chǎng)景中,同一條流水線(xiàn)的多次執(zhí)行之間是有關(guān)聯(lián)的。如果能夠用到上一次的執(zhí)行結(jié)果,則可以大幅縮短執(zhí)行時(shí)間。為了提高用戶(hù)使用流水線(xiàn)的體驗(yàn),我們加入支持緩存的功能,掛接遠(yuǎn)程儲(chǔ)存管理構(gòu)建緩存,可以實(shí)現(xiàn)同一個(gè)項(xiàng)目的編譯依賴(lài)復(fù)用,在同一條流水線(xiàn)的多次運(yùn)行中,共享同一份緩存。目標(biāo)
通過(guò)實(shí)現(xiàn)云原生流水線(xiàn)的緩存技術(shù),實(shí)現(xiàn)代碼編譯的緩存復(fù)用,平均加速流水線(xiàn) 3~5 倍;實(shí)現(xiàn)方案
我們將需要進(jìn)行緩存的文件,使用 zstd 的方式進(jìn)行壓縮,通過(guò)遠(yuǎn)程掛載 cfs,將構(gòu)建的緩存持久化到 cfs 上的指定位置。當(dāng)下一次構(gòu)建開(kāi)始的時(shí)候,判斷緩存是否被命中,如果命中緩存,我們從 cfs 上的指定位置 pull 對(duì)應(yīng)的緩存壓縮包,解壓到相應(yīng)目錄下。所用工具 - cfs+zstd
非用戶(hù)自定義鏡像,將需要的工具打到引擎的基礎(chǔ)鏡像中,作為所有鏡像的基礎(chǔ)工具。用戶(hù)自定義鏡像,不和用戶(hù)鏡像進(jìn)行強(qiáng)綁定,如果需要使用緩存功能,可以使用 Restore 緩存原子和 Save 緩存原子,設(shè)置緩存 key 和緩存目錄,實(shí)現(xiàn)緩存功能。1 cfs 遠(yuǎn)程掛載
?將工具和啟動(dòng)腳本,配置文件打到基礎(chǔ)鏡像?在開(kāi)啟緩存的位置,啟動(dòng)腳本,開(kāi)始掛載 cfs
_, err = c.ScriptAction.Sh([]string{
"sh",
"-c",
"modprobe fuse;cd /export/servers/tools/cfs;sudo ./cfs-client-randomwrite -c fuse.json",
})
2 zstd 壓縮
針對(duì)現(xiàn)有的幾種壓縮方式進(jìn)行了性能對(duì)比,最后選用了 zstd 進(jìn)行壓縮。Zstd,全稱(chēng) Zstandard,是 Facebook 于 2016 年開(kāi)源的新無(wú)損壓縮算法。Zstd 還可以以壓縮速度為代價(jià)提供更強(qiáng)的壓縮比,速度與壓縮率的比重可通過(guò)增量進(jìn)行配置。與 zlib、lz4、xz 等當(dāng)前流行的壓縮算法不同,Zstd 尋求一種壓縮性能與壓縮率通吃的方案,而實(shí)際上它也確實(shí)做到了。在由官方所列出的表格中,可以看到,Zstd 不僅具備優(yōu)秀的壓縮性能,在壓縮率上也有非常亮眼的表現(xiàn)。在過(guò)去的兩年里,Linux 內(nèi)核、HTTP 協(xié)議、以及一系列的大數(shù)據(jù)工具(包括 Hadoop 3.0.0,HBase 2.0.0,Spark 2.3.0,Kafka 2.1.0)等都已經(jīng)加入了對(duì) zstd 的支持。常見(jiàn)的壓縮算法性能對(duì)比:
壓縮包大小對(duì)比:| 依賴(lài)包的大小 | 465M | 壓縮效率 |
|---|---|---|
| tar 壓縮 | 423M | 14s 左右 |
| zstd 壓縮 | 205M | 1s 左右 |
緩存的實(shí)現(xiàn)
我們借鑒了 github cache action,zadig,gitlab 等緩存的處理方式,同時(shí)結(jié)合服務(wù)自身的特點(diǎn)將整體分成三步?檢查是否命中緩存:根據(jù)緩存 key,判斷緩存是否命中
| 緩存 key | 緩存的唯一標(biāo)識(shí) |
|---|---|
| 不同語(yǔ)言編譯原子 | 根據(jù)下載代碼的代碼庫(kù)地址自動(dòng)獲取 設(shè)置的緩存 key:home_auth/home-auth-center |
| 用戶(hù)自定義鏡像 | 自定義緩存 key |
?pull 緩存
當(dāng)緩存命中后,根據(jù)緩存路徑,找到掛載到 cfs 上的緩存壓縮包,解壓到指定的緩存目錄下?push 緩存:將依賴(lài)包進(jìn)行壓縮,放到 cfs 的掛載目錄下

| 依賴(lài)包的大小 | 465M |
|---|---|
| tar 壓縮 | 423M |
| zstd 壓縮 | 205M |

緩存的使用限制和回收策略
使用限制
目前存儲(chǔ)緩存數(shù)沒(méi)有限制,存儲(chǔ)庫(kù)中所有緩存的總大小限制是根據(jù)申請(qǐng)的 cfs 的大小限制:20G。回收策略
我們會(huì)刪除 7 天內(nèi)未被訪問(wèn)的任何緩存。利用 etcd 的 watch 機(jī)制,實(shí)現(xiàn)緩存的回收。etcd 可以Watch指定的鍵、前綴目錄的更改,并對(duì)更改時(shí)間進(jìn)行通知。BASE 引擎中,緩存的清除策略借助 etcd 來(lái)實(shí)現(xiàn)。緩存過(guò)期策略:在編譯加速的實(shí)現(xiàn)中,每個(gè)需要緩存的項(xiàng)目都有對(duì)應(yīng)的緩存 key,通過(guò) etcd 監(jiān)控 key,并且設(shè)置過(guò)期時(shí)間,例如 7 天,如果在 7 天之內(nèi)再次命中 key,則通過(guò) lease 進(jìn)行續(xù)約;7 天之內(nèi) key 都沒(méi)有被使用,key 就會(huì)過(guò)期刪除,通過(guò)監(jiān)聽(tīng)對(duì)應(yīng)的前綴,在過(guò)期刪除的時(shí)候,調(diào)用刪除緩存的方法。
storage.Watch("cache/",
func(id string) {
//do nothing
},
func(id string) {
CleanCache(id)
})
不同技術(shù)棧的最佳實(shí)踐
1 Java
以 Maven 構(gòu)建工具為例,其默認(rèn)配置文件位于 conf/settings.xml 文件中,默認(rèn)指定環(huán)境變量 $M2_HOME 來(lái)設(shè)置緩存目錄,這樣同一條流水線(xiàn)多次執(zhí)行可以復(fù)用 ${M2_HOME}/.m2 目錄 (緩存目錄),甚至同一個(gè)應(yīng)用下的多個(gè)分支之間都可以使用同一個(gè)緩存目錄,就像本地構(gòu)建一樣。| ? | BASE 執(zhí)行 |
|---|---|
| 無(wú)緩存 | 平均時(shí)間:5.26min |
| 有緩存 | 平均時(shí)間:41.462s |
| 提升效率 | 提升 87.3% |
| 緩存命中率 | 接近 100% |
2 NodeJs
在 nodejs 編譯中,我們的緩存目錄是當(dāng)前用戶(hù)空間,針對(duì) node_modules 文件進(jìn)行壓縮打包,push 到 cfs;如果緩存命中,從 cfs 上 pull 并且解壓到當(dāng)前用戶(hù)空間下,恢復(fù)緩存。使用舉例
| ? | BASE 執(zhí)行 |
|---|---|
| 無(wú)緩存 | 平均時(shí)間:58s |
| 有緩存 | 平均時(shí)間:29s |
| 提升效率 | 提升 50% |
| 緩存命中率 | 接近 100% |
3 Golang 編譯
Golang 緩存路徑通過(guò)$GOCACHE環(huán)境變量控制,將$GOCACHE的內(nèi)容壓縮成 zstd 的包,上傳到 cfs 的指定路徑下。pull 緩存的時(shí)候,拉取到對(duì)應(yīng)的$GOCACHE。| ? | BASE 執(zhí)行 |
|---|---|
| 無(wú)緩存 | 平均時(shí)間:117s |
| 有緩存 | 平均時(shí)間:18s |
| 提升效率 | 提升 84.6% |
| 緩存命中率 | 接近 100% |
4 GCC 編譯
我們使用 ccache 進(jìn)行緩存實(shí)現(xiàn)。ccache(“compilercache” 的縮寫(xiě))是一個(gè)編譯器緩存,該工具會(huì)高速緩存編譯生成的信息,并在編譯的特定部分使用高速緩存的信息。ccache 的緩存目錄:CCACHE_DIR,我們將這個(gè)目錄下的文件進(jìn)行壓縮,push 到 cfs,當(dāng)?shù)诙芜\(yùn)行并且命中緩存,從 cfs 上 pull 并解壓到 CCACHE_DIR 指定的目錄下。總結(jié)
在不同語(yǔ)言的編譯原子內(nèi)部,默認(rèn)開(kāi)啟緩存的設(shè)置。第一次運(yùn)行流水線(xiàn)的時(shí)候,會(huì)進(jìn)行依賴(lài)的下載,第二次運(yùn)行流水線(xiàn),會(huì)命中緩存,無(wú)需進(jìn)行依賴(lài)的下載,提高了流水線(xiàn)執(zhí)行的效率。緩存默認(rèn)保存 7 天。自定義鏡像進(jìn)行緩存的最佳實(shí)踐
為了滿(mǎn)足用戶(hù)使用自定義鏡像的方式觸發(fā)流水線(xiàn),我們?cè)黾恿藘蓚€(gè)通用的緩存原子。Restore 緩存:恢復(fù)緩存Save 緩存:保存緩存
在編譯之前,添加 Restore 緩存原子
在編譯之后,添加 Save 緩存原子
使用舉例
在 maven 編譯原子中,默認(rèn)開(kāi)啟了 maven 編譯的緩存;同時(shí)還有 nodejs 的編譯構(gòu)建,所以我們?cè)黾恿?restore 原子和 save 原子
| ? | BASE 執(zhí)行 |
|---|---|
| 無(wú)緩存 | 平均時(shí)間:21min57s 其中 maven: 17min83s nodejs: 4min19s |
| 有緩存 | 平均時(shí)間:4min20s 其中 maven: 1min10s nodejs: 2min36s |
| 緩存效率提升 | maven:93.7% nodejs:39.8%(nodejs 編譯中有包含單元測(cè)試) |
| 緩存命中率 | 接近 100% |
未來(lái)規(guī)劃
?不同編譯原子,向用戶(hù)開(kāi)放配置,如是否開(kāi)啟緩存,設(shè)置緩存 key
?實(shí)現(xiàn)不同語(yǔ)言編譯原子增量 push 緩存功能
審核編輯 :李倩
-
流水線(xiàn)
+關(guān)注
關(guān)注
0文章
127瀏覽量
27081 -
編譯
+關(guān)注
關(guān)注
0文章
682瀏覽量
34892 -
云原生
+關(guān)注
關(guān)注
0文章
265瀏覽量
8487
原文標(biāo)題:云原生場(chǎng)景下實(shí)現(xiàn)編譯加速
文章出處:【微信號(hào):OSC開(kāi)源社區(qū),微信公眾號(hào):OSC開(kāi)源社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
性能提升1倍,成本直降50%!基于龍蜥指令加速的下一代云原生網(wǎng)關(guān)
只需 6 步,你就可以搭建一個(gè)云原生操作系統(tǒng)原型
云原生應(yīng)用中的“云”指的是什么?
引領(lǐng)云原生2.0時(shí)代,賦能新云原生企業(yè)
云原生解決了什么問(wèn)題?
如何更好地構(gòu)建云原生應(yīng)用生態(tài),推動(dòng)業(yè)界更好地落地云原生
解讀騰訊云原生 鵝廠云原生的“新路”與“歷承”
云原生技術(shù)下的華為云DevOps實(shí)踐之路
華為云中什么是云原生服務(wù)中心

云原生場(chǎng)景下實(shí)現(xiàn)編譯加速
評(píng)論