欧美性猛交xxxx免费看_牛牛在线视频国产免费_天堂草原电视剧在线观看免费_国产粉嫩高清在线观看_国产欧美日本亚洲精品一5区

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

vivo AI計(jì)算平臺的K8s分級配額管理實(shí)踐

jf_WZTOguxH ? 來源:AI前線 ? 作者:AI前線 ? 2023-03-07 09:56 ? 次閱讀

2018 年底,vivo AI 研究院為了解決統(tǒng)一高性能訓(xùn)練環(huán)境、大規(guī)模分布式訓(xùn)練、計(jì)算資源的高效利用調(diào)度等痛點(diǎn),著手建設(shè) AI 計(jì)算平臺。經(jīng)過四年多的持續(xù)迭代,平臺建設(shè)和落地取得了很大進(jìn)展,成為 vivo AI 領(lǐng)域的核心基礎(chǔ)平臺。平臺從當(dāng)初服務(wù)深度學(xué)習(xí)訓(xùn)練為主,到現(xiàn)在演進(jìn)成包含 VTraining、VServing、VContainer 三大模塊,對外提供模型訓(xùn)練、模型推理和容器化能力的基礎(chǔ)設(shè)施。平臺的容器集群有數(shù)千個(gè)節(jié)點(diǎn),擁有超過數(shù)百 PFLOPS 的 GPU 算力。集群里同時(shí)運(yùn)行著數(shù)千個(gè)訓(xùn)練任務(wù)和數(shù)百個(gè)在線服務(wù)。本文是 vivo AI 計(jì)算平臺實(shí)戰(zhàn) 系列文章之一,主要分享了平臺在資源配額管理方面的實(shí)踐。

背 景

K8s 提供了原生的 ResourceQuota 資源配額管理功能,基于命名空間進(jìn)行配額管理,簡單易用。但是隨著平臺資源使用場景變得越來越復(fù)雜,例如多層級業(yè)務(wù)組織配額、針對具體 CPU 核和 GPU 卡的型號配額、資源使用時(shí)長配額等,ResourceQuota 變得難以應(yīng)對,平臺面臨業(yè)務(wù)資源爭搶、配額管理成本增加、定位問題效率變低等問題。

本文主要介紹平臺在 K8s 集群資源配額管理過程中遇到的問題,以及如何實(shí)現(xiàn)符合需求的配額管理組件:BizGroupResourceQuota —— 業(yè)務(wù)組資源配額(簡稱 bizrq),用于支撐平臺對復(fù)雜資源使用場景的配額管控。

ResourceQuota 資源配額管理遇到的問題

在使用 ResourceQuota 做資源配額管理時(shí),有以下 4 個(gè)問題比較突出:

1、無法滿足有層級的業(yè)務(wù)組織架構(gòu)的資源配額管理

ResourceQuota 不能很好地應(yīng)用于樹狀的業(yè)務(wù)組織架構(gòu)場景,因?yàn)槊臻g是扁平的,在實(shí)際場景中,我們希望將資源配額由父業(yè)務(wù)組到子業(yè)務(wù)組進(jìn)行逐級下發(fā)分配。

2、以 pod 對象的粒度限額可能導(dǎo)致只有部分 pod 創(chuàng)建成功

ResourceQuota 是以 pod 對象的粒度來進(jìn)行資源限額的,正常情況下在線服務(wù)或離線任務(wù)的部署,例如 deployment、argo rollout、tfjob 等,都需要批量創(chuàng)建 pod,可能會造成一部分 pod 由于額度不足而創(chuàng)建失敗的情形,導(dǎo)致部署無法完成甚至失敗,我們希望要么全部 pod 都創(chuàng)建成功,要么直接拒絕部署并提示資源額度不足,提升部署體驗(yàn)。

3、無法針對具體 CPU 核和 GPU 卡的型號進(jìn)行配額管理

ResourceQuota 管理配額的資源粒度太粗,無法針對具體 CPU 核和 GPU 卡的型號進(jìn)行配額管理,在實(shí)際場景中,不同的 CPU、GPU 型號的性能、成本差異很大,需要分開進(jìn)行限額。例如我們會將 CPU 機(jī)器劃分為 A1、A2、A3、A4 等機(jī)型,GPU 機(jī)器也有 T4、V100、A30、A100 等機(jī)型,他們的性能和成本都是有差異的。

4、無法限制資源使用時(shí)長

ResourceQuota 僅能限制當(dāng)前時(shí)刻資源的已使用額度不能超過配額,但是并不能限制對資源的使用時(shí)長。在某些離線的深度模型訓(xùn)練場景,業(yè)務(wù)對 CPU、GPU 資源爭搶比較激烈,某些業(yè)務(wù)組希望能按 CPU 核時(shí)或 GPU 卡時(shí)的方式,給團(tuán)隊(duì)成員發(fā)放資源配額,比如每人每周發(fā)放 1000 GPU 卡時(shí),表示可以用 10 張卡跑 100 小時(shí),也可用 20 張卡跑 50 小時(shí),以此類推。

BizGroupResourceQuota 分級配額管理方案

針對 ResourceQuota 配額管理所面臨的 4 個(gè)問題,我們設(shè)計(jì)了 BizGroupResourceQuota 配額管理 —— 業(yè)務(wù)組資源配額管理方案,后文簡稱為 bizrq。接下來,我們介紹一下 bizrq 方案。

我們通過 K8s crd(Custom Resource Define)來自定義 bizrq 資源對象(如下圖 bizrq 配額示例),從而定義 bizrq 的實(shí)現(xiàn)方案:

557efac6-bc7d-11ed-bfe3-dac502259ad0.png

如上圖配額示例所示,下面分別解釋一下 bizrq 配額方案的特點(diǎn):

① bizrq name

bizrq name 在 cluster scope 全局唯一,bizrq 配額對象是集群范圍的,不跟命名空間相關(guān)聯(lián)。在實(shí)際業(yè)務(wù)場景中,bizrq name 可以跟業(yè)務(wù)組 ID 對應(yīng)起來,便于實(shí)現(xiàn)基于樹狀的業(yè)務(wù)組織架構(gòu)的配額管理。

②父 bizrq name

父 bizrq name 表示當(dāng)前 bizrq 的父級業(yè)務(wù)組的 bizrq 配額對象名稱,假如父 bizrq name 值設(shè)置了空字符串"",則表示當(dāng)前 bizrq 是 root 節(jié)點(diǎn)。當(dāng)創(chuàng)建非 root 的 bizrq 配額對象時(shí),子 bizrq 的資源配額要從父 bizrq 的剩余額度中申請,并需要滿足相關(guān)約束條件才能創(chuàng)建成功,后面也會介紹實(shí)現(xiàn)原理。這樣就可以按常見的業(yè)務(wù)組織架構(gòu)來管理配額,構(gòu)成一顆“bizrq 樹”:

559785be-bc7d-11ed-bfe3-dac502259ad0.png

③默認(rèn)配額示例

默認(rèn)配額示例跟 ResourceQuota 的資源額度配置和限額效果是一致的,bizrq 借鑒了 ResourceQuota 的實(shí)現(xiàn),保持了一致的配置風(fēng)格和使用體驗(yàn)。

④ CPU核型號配額示例

bizrq 支持將 CPU 核配額限制到具體型號,具體型號資源的已使用額度,也會累加到前綴相同的通用資源配額的已使用額度里,它們是可以結(jié)合使用的,如果都配置了則限額會同時(shí)生效。這樣即保留了原生 ResourceQuota 的限額功能,又新增了不同型號資源的限額。

舉例說明,比如將 limits.cpu 配額設(shè)置為 10 核,limits.cpu.A4 配額設(shè)置為 4 核,它們一開始已使用額度都是 0 核,當(dāng)我們的部署對象申請了 4 核的 A4 后,那么 limits.cpu 和 limits.cpu.A4 的已使用額度都會累加上這 4 核,因?yàn)?bizrq 會判斷 limits.cpu 是 limits.cpu.A4 的前綴資源,屬于通用資源類型,所以要一并計(jì)算。另外,此時(shí)業(yè)務(wù)組不能再申請 A4 型號的 cpu 資源了,因?yàn)?limits.cpu.A4 的剩余額度為 0,不過 limits.cpu 剩余額度還有 6 核,所以還可以申請非 A4 型號的 CPU 資源。

那么我們能否將 limits.cpu 配額設(shè)置為 10 核,將 limits.cpu.A4 配額設(shè)置為 100 核呢(limits.cpu < limits.cpu.A4)?是可以這樣配置的,但是將 limits.cpu.A4 配置為 100 核沒有意義,因?yàn)樯暾?A4 型號的 CPU 資源時(shí),bizrq 也會分析前綴相同的 limits.cpu 的剩余額度是否足夠,如果額度不足那么任何型號的 CPU 資源都不能申請成功。

⑤GPU 卡型號配額示例

bizrq 支持將 GPU 卡配額限制到具體型號,具體型號資源的已使用額度,也會累加到前綴相同的通用資源的已使用額度里,它們是可以結(jié)合使用的,跟上面介紹的 CPU 核型號的限額行為也是一致的。

⑥GPU 卡時(shí)配額示例,⑦CPU 核時(shí)配額示例

bizrq 支持虛擬 cash 機(jī)制,可以給業(yè)務(wù)組分配 CPU 核時(shí)、GPU 卡時(shí)等“虛擬的貨幣”,比如給某個(gè)業(yè)務(wù)組分配 100CPU 核時(shí):“cash/limits.cpu: 100”,(注意前綴 “cash/” 的表示)表示這個(gè)業(yè)務(wù)組的業(yè)務(wù)可以用 1 個(gè) CPU 核跑 100 小時(shí),也可以用 2 個(gè) CPU 核跑 50 小時(shí),還可以用 100 個(gè) CPU 核跑 1 小時(shí),GPU 卡時(shí)的定義可以類比。

⑧指定 Deployment 關(guān)聯(lián)的配額對象(bizrq name)

bizrq 限額不以 pod 對象為粒度進(jìn)行限額,而是以 deployment、argo rollout、tfjob 等上層部署對象的粒度來限額,需要通過部署對象 label “biz.group.resource.quota”來關(guān)聯(lián) bizrq 配額對象(注意不是通過命名空間進(jìn)行關(guān)聯(lián),因?yàn)?bizrq 是 cluster scope 的)。

通過攔截上層部署對象的創(chuàng)建、更新操作進(jìn)行資源額度的校驗(yàn)(通過 validating webhook 攔截,后文會介紹實(shí)現(xiàn)原理),當(dāng)關(guān)聯(lián) bizrq 的剩余資源額度充足時(shí),允許上層對象的創(chuàng)建;當(dāng)剩余資源額度不足時(shí),拒絕上層對象的創(chuàng)建,從而防止只有部分 pod 創(chuàng)建成功的情形。

⑨⑩指定部署對象關(guān)聯(lián)的配額對象(bizrq name)

為了達(dá)到具體的 CPU 核型號或 GPU 卡型號的限額目的,也要給部署對象打上聲明具體的資源型號的 label,例如:biz.group.resource.quota/cpu-type: "A4",表示部署對象申請的是 A4 型號的 CPU 核;或 GPU 卡型號的 label,例如:biz.group.resource.quota/gpu-type: "A30",表示部署對象申請的是 A30 型號的 GPU 卡。

備注:bizrq 同樣支持具體的內(nèi)存類型的限額,使用方式與 CPU 核、GPU 卡類型的限額類似,比如可以設(shè)置 limits.memory.A4 的額度,然后給部署對象打上聲明具體的資源型號的 label:biz.group.resource.quota/memory-type: "A4" 即可。

配額機(jī)制實(shí)現(xiàn)原理

bizrq 方案在 ResourceQuota 所支持的基礎(chǔ)資源配額的基礎(chǔ)上,增加了(1)父子關(guān)系的表示,(2)CPU 核和 GPU 卡型號的限額,(3)核時(shí)、卡時(shí)的限額,(4)針對上層的部署資源對象進(jìn)行額度校驗(yàn),而不是針對單個(gè) pod;同時(shí) bizrq 對象的配置風(fēng)格和 ResourceQuota 對象的配置風(fēng)格是一樣的,易于配置和理解。所以 bizrq 分級配額的實(shí)現(xiàn)思路應(yīng)該也是可以借鑒 ResourceQuota 的,在分析 bizrq 實(shí)現(xiàn)前,我們先分析下 ResourceQuota 的實(shí)現(xiàn)原理,以便借鑒官方優(yōu)秀的實(shí)現(xiàn)思路。

原生 ResourceQuota 實(shí)現(xiàn) 整體架構(gòu)

55a72c6c-bc7d-11ed-bfe3-dac502259ad0.png

如上圖所示,APIServer 接收到資源對象請求后,由訪問控制鏈路中的處理器按順序進(jìn)行處理,請求順利通過訪問控制鏈路的處理后,資源對象的變更才允許被持久化到 etcd,它們依次是認(rèn)證(authentication)→鑒權(quán)(authorization)→變更準(zhǔn)入控制(mutating admission)→對象 Schema 校驗(yàn)(object schema validation)→驗(yàn)證準(zhǔn)入控制(validating admission)→etcd 持久化,我們需要重點(diǎn)關(guān)注“準(zhǔn)入控制”環(huán)節(jié):

? 變更準(zhǔn)入控制(mutating admission):對請求的資源對象進(jìn)行變更。例如內(nèi)置的 ServiceAccount admission controller,會將 pod 的默認(rèn) ServiceAccount 設(shè)為 default,并為每個(gè)容器添加 volumeMounts,掛載至 /var/run/secrets/kubernetes.io/serviceaccount,以便在 pod 內(nèi)部可以讀取到身份信息來訪問當(dāng)前集群的 apiserver。變更準(zhǔn)入控制是可擴(kuò)展的,我們可以通過配置 mutating admission webhooks 將自定義的邏輯加入到變更準(zhǔn)入控制鏈路中;

? 驗(yàn)證準(zhǔn)入控制(validating admission):對請求的資源對象進(jìn)行各種驗(yàn)證。此環(huán)節(jié)不會去變更資源對象,而是做一些邏輯校驗(yàn),例如接下來要分析的 QuotaAdmission Controller,會攔截 pod 的創(chuàng)建請求,計(jì)算 pod 里容器申請的資源增量是否會導(dǎo)致超額。驗(yàn)證準(zhǔn)入控制也是可擴(kuò)展的,我們可以通過配置 validating admission webhooks 將自定義的邏輯加入到驗(yàn)證準(zhǔn)入控制鏈路中。

如上圖所示,ResourceQuota 限額機(jī)制主要由兩個(gè)組件組成:

? ResourceQuota Controller:ResourceQuota Controller 是內(nèi)置在 controller manager 眾多 Controllers 中的一個(gè),主要負(fù)責(zé)監(jiān)聽資源對象,如 pod、service 等變更事件,也包括 ResourceQuota 對象的變更事件,以便及時(shí)刷新關(guān)聯(lián)的 ResourceQuota 的 status 狀態(tài);

? QuotaAdmission Controller:QuotaAdmission 是內(nèi)置在 apiserver 請求訪問控制鏈路驗(yàn)證準(zhǔn)入控制環(huán)節(jié)的控制器,QuotaAdmission 主要負(fù)責(zé)攔截資源對象的創(chuàng)建、更新請求,對關(guān)聯(lián) ResourceQuota 的額度進(jìn)行校驗(yàn)。

下面以 Pod 對象的限額為例,分析 ResourceQuota 限額機(jī)制原理。其他資源,比如 service、pvc 等對象限額的實(shí)現(xiàn)思路基本一致,只不過不同對象有不同的資源計(jì)算邏輯實(shí)現(xiàn)(Evaluator)。

ResourceQuota Controller

當(dāng)集群的 controller manager 進(jìn)程啟動(dòng)后,選主成功的那個(gè) controller manager leader 就會將包括 ResourceQuota Controller 在內(nèi)的所有內(nèi)置的 Controller 跑起來,ResourceQuota Controller 會以生產(chǎn)者 - 消費(fèi)者的模式,不斷刷新集群命名空間的 ResourceQuota 對象的資源使用狀態(tài):

560a5cce-bc7d-11ed-bfe3-dac502259ad0.png

作為任務(wù)生產(chǎn)者,為了及時(shí)把需要刷新狀態(tài)的 ResourceQuota 放到任務(wù)隊(duì)列,ResourceQuota Controller 主要做了以下 3 件事情:

· 監(jiān)聽 pod 對象的事件,當(dāng)監(jiān)聽到 pod 由占用資源狀態(tài)變更為不占資源狀態(tài)時(shí),比如 status 由 terminating 變?yōu)?Failed、Succeeded 狀態(tài),或者 pod 被刪除時(shí),會將 pod 所在命名空間下關(guān)聯(lián)的所有 ResourceQuota 放入任務(wù)隊(duì)列;

·監(jiān)聽 ResourceQuota 對象的創(chuàng)建、spec.Hard 更新(注意會忽略 status 更新事件,主要是為了將 spec.Hard 刷新到 status.Hard)、delete 等事件,將對應(yīng)的 ResourceQuota 放入任務(wù)隊(duì)列;

·定時(shí)(默認(rèn) 5m,可配置)把集群所有的 ResourceQuota 放入任務(wù)隊(duì)列,確保 ResourceQuota 的狀態(tài)最終是跟命名空間實(shí)際資源使用情況一致的,不會因?yàn)楦鞣N異常情況而出現(xiàn)長期不一致的狀態(tài)。

作為任務(wù)消費(fèi)者,ResourceQuota Controller 會為任務(wù)隊(duì)列啟動(dòng)若干 worker 協(xié)程(默認(rèn) 5 個(gè),可配置),不斷從任務(wù)隊(duì)列取出 ResourceQuota,計(jì)算 ResourceQuota 所在命名空間所有 pod 的容器配置的資源量來刷新 ResourceQuota 的狀態(tài)信息。

QuotaAdmission Controller

對于 pod 的限額,QuotaAdmission 只會攔截 Pod create 操作,不會攔截 update 操作,因?yàn)楫?dāng)部署對象的 pod 容器資源申請被變更后,原 pod 是會被刪除并且創(chuàng)建新 pod 的,pod 的刪除操作也不用攔截,因?yàn)閯h除操作肯定不會導(dǎo)致超額。

當(dāng) QuotaAdmission 攔截到 Pod 的創(chuàng)建操作后,會找出對應(yīng)命名空間所有相關(guān)聯(lián)的 ResourceQuota,并分析創(chuàng)建 pod 會不會造成資源使用超額,只要有一個(gè) ResourceQuota 會超額,那么就拒絕創(chuàng)建操作。如果所有的 ResourceQuota 都不會超額,那么先嘗試更新 ResourceQuota 狀態(tài),即是將此個(gè) pod 的容器配置的資源量累加到 ResourceQuota status.Used 里,更新成功后,放行此次 pod 操作。

問題分析

總的來說,ResourceQuota Controller 負(fù)責(zé)監(jiān)聽各類對象的變更事件,以便能及時(shí)刷新對應(yīng)的 ResourceQuota status 狀態(tài),而 QuotaAdmission 則負(fù)責(zé)攔截對象操作,做資源額度的校驗(yàn)。有幾個(gè)比較關(guān)鍵的問題我們需要分析一下,這幾個(gè)問題也是 bizrq 實(shí)現(xiàn)的關(guān)鍵點(diǎn):

1、ResourceQuota status 的并發(fā)安全問題

ResourceQuota Controller 會不斷刷新 ResourceQuota status 里各類資源使用量,所有 apiserver 進(jìn)程的 QuotaAdmission 也會根據(jù) ResourceQuota status 校驗(yàn)是否超額,并將校驗(yàn)通過的 pod 資源增量累加到 ResourceQuota status.Used,所以 status 的更新是非常頻繁的,這就會導(dǎo)致并發(fā)安全問題:

假設(shè)某個(gè)業(yè)務(wù)組 CPU 配額有 10 核,已使用量為 1 核,業(yè)務(wù) A 和業(yè)務(wù) B 同時(shí)請求申請 5 核,此時(shí)對剩余額度的校驗(yàn)都是足夠的(剩余 CPU 核數(shù)為 10-1=9),兩個(gè)請求都會將 CPU 已使用量更新為 1+5=6 核,并且都申請成功,這將導(dǎo)致限額失效,因?yàn)閷?shí)際的資源申請已經(jīng)超額了(1+5+5=11 核)。

解決辦法通常有以下 3 種方式:

·方式 1:將所有對 status 的訪問邏輯打包成任務(wù)放入隊(duì)列,并通過單點(diǎn)保證全局按順序進(jìn)行處理;

·方式 2:將所有對 status 的訪問邏輯加鎖,獲取到鎖才可以進(jìn)行處理,保證任何時(shí)刻都不會有并發(fā)的訪問;

·方式 3:通過樂觀鎖來確保對 status 的訪問是安全的。

ResourceQuota 采用的是第三種方式,方式 1、2 都要引入額外的輔助手段,比如分布式隊(duì)列、分布式鎖,并且同一時(shí)刻只能處理一個(gè)請求,效率比較低下,容易造成處理延時(shí),此外還要考慮 ResourceQuota Controller 跟 QuotaAdmission Controller 的協(xié)同(都會更新 ResourceQuota status.Used),在限額場景實(shí)現(xiàn)起來不是那么簡潔高效,而方式 3 可以直接基于 K8s 的樂觀鎖來達(dá)到目的,是最簡潔高效的方式。

K8s 樂觀鎖實(shí)現(xiàn)原理

K8s 樂觀鎖的實(shí)現(xiàn),有兩個(gè)前提:

·一是 K8s 資源對象的 resourceVersion 是基于 etcd 的 revision,revision 的值是全局單調(diào)遞增的,對任何 key 的修改都會使其自增;

·二是 apiserver 需要通過 etcd 的事務(wù) API,即 clientv3.KV.Txn(ctx).If(cmp1, cmp2, ......).Then(op1, op2, ......).Else(op1, op2, ......),來實(shí)現(xiàn)事務(wù)性的比較更新操作。

具體流程示例如下:

561b1eec-bc7d-11ed-bfe3-dac502259ad0.png

·第 1 步:client 端從 apiserver 查詢出對象 obj 的值 d0,對應(yīng)的 resourceVersion 為 v0;

·第 2 步:client 端本地處理業(yè)務(wù)邏輯后,調(diào)用 apiserver 更新接口,嘗試將對象 obj 的值 d0 更新為 dx;

·第 3 步:apiserver 接受到 client 端請求后,通過 etcd 的 if...then...else 事務(wù)接口,判斷在 etcd 里對象 obj 的 resourceVersion 值是否還是 v0,如果還是 v0,表示對象 obj 沒被修改過,則將對象 obj 的值更新為 dx,并為對象 obj 生成最新的 resourceVersion 值 v1;如果 etcd 發(fā)現(xiàn)對象 obj 的 resourceVersion 值已經(jīng)不是 v0,那么表示對象 obj 已經(jīng)被修改過,此時(shí) apiserver 將返回更新失敗;

·第 4 步:對于 client 端,apiserver 返回更新成功時(shí),對象 obj 已經(jīng)被成功更新,可以繼續(xù)處理別的業(yè)務(wù)邏輯;如果 apiserver 返回更新失敗,那么可以選擇重試,即重復(fù) 1~4 步的操作,直到對象 obj 被成功。

apiserver 的更新操作實(shí)現(xiàn)函數(shù):

https://github.com/kubernetes/kubernetes/blob/v1.20.5/staging/src/k8s.io/apiserver/pkg/storage/etcd3/store.go

56251c6c-bc7d-11ed-bfe3-dac502259ad0.png

相對于方式 2 的鎖(悲觀鎖),樂觀鎖不用去鎖整個(gè)請求操作,所有請求可以并行處理,更新數(shù)據(jù)的操作可以同時(shí)進(jìn)行,但是只有一個(gè)請求能更新成功,所以一般會對失敗的操作進(jìn)行重試,比如 QuotaAdmission 攔截的用戶請求,加了重試機(jī)制,重試多次不成功才返回失敗,在并發(fā)量不是非常大,或者讀多寫少的場景都可以大大提升并發(fā)處理效率。

QuotaAdmission 中樂觀鎖重試機(jī)制實(shí)現(xiàn)函數(shù)是 checkQuotas,感興趣可自行閱讀源碼:

https://github.com/kubernetes/kubernetes/blob/v1.20.5/staging/src/k8s.io/apiserver/pkg/admission/plugin/resourcequota/controller.go

568565a4-bc7d-11ed-bfe3-dac502259ad0.png

另外,更新沖突在所難免,客戶端可以借助 client-go 的 util 函數(shù) RetryOnConflict 來實(shí)現(xiàn)失敗重試:

https://github.com/kubernetes/client-go/blob/kubernetes-1.20.5/util/retry/util.go

569b579c-bc7d-11ed-bfe3-dac502259ad0.png

2、超額問題

問題:QuotaAdmission 校驗(yàn) pod 創(chuàng)建是否超額時(shí),查詢出來的 ResourceQuota 的 status.Used 狀態(tài)能否反映命名空間下資源最新實(shí)際使用量,會不會造成超額情形?

問題分析:

由于 ResourceQuota Controller 和 QuotaAdmission 都會不斷刷新 ResourceQuota 的 status.Used 狀態(tài),并且 QuotaAdmission 基本是通過 informer cache 來獲取 ResourceQuota 的,informer 監(jiān)聽會有延遲,所以校驗(yàn)額度時(shí)查詢的 ResourceQuota status 狀態(tài)可能并不是準(zhǔn)確反映命名空間下資源最新實(shí)際使用量,概括起來有以下 3 種不一致的情況:

·(1) informer 事件監(jiān)聽延遲,查詢到的可能不是 etcd 最新的 ResourceQuota;

·(2)即使查詢到的是 etcd 最新的 ResourceQuota,在額度校驗(yàn)過程中,ResourceQuota 也有可能先被別的請求或被 ResourceQuota controller 修改掉,那么 ResourceQuota 數(shù)據(jù)也是“過期”的;

·(3)即使查詢到的是 etcd 最新的 ResourceQuota,并且在額度校驗(yàn)過程中,ResourceQuota 數(shù)據(jù)沒有被修改,這個(gè)查詢出來的 etcd 最新的 ResourceQuota,也有可能不是最新的數(shù)據(jù),因?yàn)?ResourceQuota controller 刷新 ResourceQuota 可能不是那么及時(shí)。

對于(1)、(2)這兩種情形,由于 QuotaAdmission 基于 K8s 樂觀鎖做 ResourceQuota 資源額度的校驗(yàn)及狀態(tài)更新,如果 ResourceQuota 不是 etcd 最新的,那么更新 ResourceQuota 狀態(tài)時(shí)會失敗,QuotaAdmission 將進(jìn)行重試,這樣就能保證只有用最新的 ResourceQuota 來做額度校驗(yàn),資源申請請求才能被通過;

對于(3)情形,ResourceQuota controller 刷新 ResourceQuota 可能不及時(shí),但也不會造成超額,因?yàn)橘Y源使用量的增加(例如 pod 創(chuàng)建操作)都是要通過 QuotaAdmission 攔截校驗(yàn)并通過樂觀鎖機(jī)制將資源增量更新到 ResourceQuota,ResourceQuota controller 刷新 ResourceQuota 不及時(shí),只會導(dǎo)致當(dāng)前 etcd 最新 ResourceQuota 的剩余額度比實(shí)際“偏小”(例如 pod 由 terminating 變?yōu)?Failed、Succeeded 狀態(tài),或者 pod 被刪除等情形),所以符合我們限額的目的。

當(dāng)然,如果手動(dòng)把配額調(diào)小,那可能會人為造成超額現(xiàn)象,比如原先 CPU 配額 10 核,已使用 9 核,此時(shí)手動(dòng)把配額改成 8 核,那么 QuotaAdmission 對于之后的 pod 創(chuàng)建的額度校驗(yàn)肯定因?yàn)橐呀?jīng)超額,不會通過操作了,不過這個(gè)是預(yù)期可理解的,在實(shí)際業(yè)務(wù)場景也有用處。

3、全局刷新問題

問題:為什么要定時(shí)全量刷新集群所有的 ResourceQuota 狀態(tài)?

問題分析:

·定時(shí)全量刷新可以防止某些異常導(dǎo)致的 ResourceQuota status 跟實(shí)際的資源使用狀態(tài)不一致的情形,保證狀態(tài)回歸一致性。例如 QuotaAdmission 更新了 ResourceQuota 后(額度校驗(yàn)通過后),實(shí)際的資源操作由于遇到異常而沒有成功的情形(如 pod 創(chuàng)建操作在后續(xù)環(huán)節(jié)失敗的場景);

·不過由于 ResourceQuota Controller 會不斷更新 ResourceQuota,在額度校驗(yàn)通過后到實(shí)際資源操作被持久化前這段時(shí)間內(nèi)(這段時(shí)間很短),ResourceQuota 可能會被 ResourceQuota Controller 更新回舊值,如果后續(xù)有新的資源申請操作,就可能造成超額情形,不過出現(xiàn)這個(gè)問題的幾率應(yīng)該很小,通過業(yè)務(wù)層補(bǔ)償處理(比如超額告警、回收資源)即可。

關(guān)于 ResourceQuota Controller 和 QuotaAdmission 的代碼細(xì)節(jié),感興趣可以自行閱讀:

https://github.com/kubernetes/kubernetes/blob/v1.20.5/cmd/kube-controller-manager/app/core.go

56b94248-bc7d-11ed-bfe3-dac502259ad0.png

https://github.com/kubernetes/kubernetes/blob/v1.20.5/staging/src/k8s.io/apiserver/pkg/admission/plugin/resourcequota/admission.go

56d1e8c0-bc7d-11ed-bfe3-dac502259ad0.png

bizrq 實(shí)現(xiàn)

在分析了 ResourceQuota 的實(shí)現(xiàn)原理后,我們再看看如何實(shí)現(xiàn) bizrq 的限額方案。

整體架構(gòu)

參考 ResourceQuota 的實(shí)現(xiàn),我們可以將 bizrq 按功能職責(zé)劃分成 3 個(gè)模塊:

56dbbe54-bc7d-11ed-bfe3-dac502259ad0.png

bizrq controller

負(fù)責(zé)監(jiān)聽相關(guān)事件,及時(shí)刷新 bizrq 狀態(tài)以及定時(shí)(默認(rèn) 5m)刷新整個(gè)集群的 bizrq 狀態(tài)。

·監(jiān)聽 bizrq 的創(chuàng)建、更新(Spec.Hard 變更),及時(shí)刷新 bizrq status;

·監(jiān)聽部署對象,例如 deployment、argo rollout、tfjob 等對象的更新(這里僅監(jiān)聽 biz.group.resource.quota label 配置的更新)、刪除事件,及時(shí)刷新關(guān)聯(lián)的 bizrq status。

bizrq validating admission webhook(server)

基于 apiserver 的驗(yàn)證準(zhǔn)入控制 webhook,負(fù)責(zé)攔截 bizrq 的增刪改事件,做 bizrq 本身以及 bizrq parent 相關(guān)的約束性校驗(yàn),從而實(shí)現(xiàn)分級配額。

·攔截創(chuàng)建事件:對 bizrq name 做重名校驗(yàn),確保 cluster scope 全局唯一;然后進(jìn)行父 bizrq 校驗(yàn);

·攔截更新事件:確保父 parentBizGroup 字段不能變更,不能更改父 bizrq;然后進(jìn)行父 bizrq 校驗(yàn);

·攔截刪除事件:確保只能刪除葉子節(jié)點(diǎn)的 bizrq,防止不小心將一棵樹上所有的 bizrq 刪除;然后進(jìn)行父 bizrq 校驗(yàn);

·父 bizrq 校驗(yàn):校驗(yàn)非 root bizrq(Spec.ParentBizGroup 字段不為 "")的父 bizrq 的相關(guān)約束條件是否滿足:

父 bizrq 必須已存在;

子 bizrq 必須包含父 bizrq 配額配置的所有資源類型名稱 key(Spec.Hard 的 key 集合),父 bizrq 的配額配置是子 bizrq 配額配置的子集,例如父 bizrq 包含 limits.cpu.A4,則創(chuàng)建子 bizrq 時(shí)也必須包含 limits.cpu.A4;

父 bizrq 的剩余額度必須足夠,子 bizrq 申請的額度是從父 bizrq 里扣取的額度。如果父 bizrq 不會超額,則先更新父 bizrq 的 status,更新成功才表示從父 bizrq 申請到了額度。

object validating admission webhooks(server)

基于 apiserver 的驗(yàn)證準(zhǔn)入控制 webhook,負(fù)責(zé)攔截需要限額的資源對象的創(chuàng)建和更新事件,例如 deployment、argo rollout、tfjob 等對象的攔截,做額度校驗(yàn),從而實(shí)現(xiàn)部署對象的限額校驗(yàn),而不是 pod 對象粒度的校驗(yàn)。

攔截到部署對象的請求時(shí),從部署對象提取出以下信息,就能計(jì)算各類資源的增量:

·資源型號(如果有指定具體型號的話),從 label biz.group.resource.quota/cpu-type 或 biz.group.resource.quota/gpu-type 提??;

·部署對象的副本數(shù)(obj.Spec.Replicas);

·PodTemplateSpec,用來計(jì)算容器配置的資源量。

然后再判斷部署對象的請求是否會導(dǎo)致關(guān)聯(lián)的 bizrq 超額(從 label biz.group.resource.quota 提取關(guān)聯(lián)的 bizrq name),如果 bizrq 不會超額,那么先嘗試更新 bizrq 資源使用狀態(tài),更新成功后,放行此次請求操作。

關(guān)于核時(shí)、卡時(shí)的限額實(shí)現(xiàn)

controller 會不斷刷新 bizrq 的 status,bizrq 的 status 跟 ResourceQuota 的 status 有點(diǎn)不一樣,bizrq 的 status 添加了一些輔助信息,用來計(jì)算核時(shí)、卡時(shí)的使用狀態(tài)(cash 額度使用狀態(tài)):

56fbac0a-bc7d-11ed-bfe3-dac502259ad0.png

對比 ResourceQuota 的 status:

·bizrq status 包含了 ResourceQuota 也有的 hard、used 字段;

·增加 selfUsed 字段來記錄 bizrq 本身(業(yè)務(wù)組本身)已使用資源量,selfUsed 不包含子 bizrq 所申請的配額,并滿足關(guān)系:selfUsed + 子 bizrq 申請的配額 = used;

·增加 lastReconcileTime 字段來記錄 controller 最后一次刷新 bizrq status 的時(shí)間,因?yàn)橛?jì)算核時(shí)、卡時(shí)是要基于資源量乘于使用時(shí)間來計(jì)算的,而且是要基于 selfUsed 累加的。計(jì)算 cash 時(shí),controller 會將部署對象包含的所有 pod 查詢出來,然后結(jié)合 lastReconcileTime、pod 開始占用資源的時(shí)間點(diǎn)(成功調(diào)度到節(jié)點(diǎn)上)、pod 釋放資源的時(shí)間點(diǎn)(比如 Succeeded、Failed),再結(jié)合 pod 容器配置的資源量,從而計(jì)算出整個(gè) bizrq 業(yè)務(wù)組較準(zhǔn)確的 cash 使用量。注意 cash 的計(jì)算不是百分百精確的,有些情形,例如 pod 被刪除了,那么下個(gè)計(jì)算周期這個(gè) pod 的 cash 就不會累加到 status 了,不過由于 controller 更新 status 的頻率很高(最遲每 5m 更新一次),所以少量誤差并不會影響大部分業(yè)務(wù)場景下的 cash 限額的需求;

·object validating admission webhooks 攔截到請求后進(jìn)行核時(shí)、卡時(shí)的額度校驗(yàn)時(shí),判斷 bizrq.status.used 里相關(guān)資源類型的 cash(如 cash/limits.cpu)是否已經(jīng)大于等于 bizrq.status.hard 里配置的配額,是則表示 cash 已經(jīng)超額,直接拒絕攔截的請求即可;

·另外,當(dāng) cash 已經(jīng)超額時(shí),并不能強(qiáng)制把相應(yīng)業(yè)務(wù)組正在運(yùn)行的業(yè)務(wù)停掉,而是可以通過監(jiān)控告警的等手段通知到業(yè)務(wù)方,由業(yè)務(wù)方自行決定如何處置。

開發(fā)工具簡介

kubebuilder

Kubebuilder 是一個(gè)基于 CRD 搭建 controller、admission webhook server 腳手架的工具,可以按 K8s 社區(qū)推薦的方式來擴(kuò)展實(shí)現(xiàn)業(yè)務(wù)組件,讓用戶聚焦業(yè)務(wù)層邏輯,底層通用的邏輯已經(jīng)直接集成到腳手架里。

bizrq 主要用到了 kubebuilder 的以下核心組件 / 功能:

· manager:負(fù)責(zé)管理 controller、webhook server 的生命周期,初始化 clients、caches,當(dāng)我們要集成不同資源對象的 client、cache 時(shí),只需寫一行代碼將資源對象的 schema 注冊一下就可以了;

· caches:根據(jù)注冊的 scheme(schema 維護(hù)了 GVK 與對應(yīng) Go types 的映射) 同步 apiserver 中所有關(guān)心的 GVK(對象類型)的 GVR(對象實(shí)例),維護(hù) GVK -> Informer 的映射;

· clients:封裝了對象的增刪改查操作接口,執(zhí)行查詢操作時(shí),底層會通過 cache 查詢,執(zhí)行變更類操作時(shí),底層會訪問 apiserver;

· indexer:可以通過 indexer 給 cache 加索引提升本地查詢效率,例如實(shí)現(xiàn) bizrq 功能時(shí),可以通過建立父子關(guān)系索引,方便通過父查找所有子 bizrq;

· controller:controller 的腳手架,提供腳手架讓業(yè)務(wù)層只需要關(guān)注感興趣的事件(任務(wù)生產(chǎn)),及實(shí)現(xiàn) Reconcile 方法(任務(wù)消費(fèi)),以便對 crd 定義的對象進(jìn)行狀態(tài)調(diào)和;

· webhook server:webhook server 的腳手架,業(yè)務(wù)層只需要實(shí)現(xiàn) Handler 接口,以便對攔截的請求做處理。

code-generator

實(shí)現(xiàn)了 bizrq 組件之后,可以通過 code-generator 工具生成 bizrq 的 informer、lister、clientset 等客戶端代碼,以便其他應(yīng)用進(jìn)行集成:

· client-gen:生成 crd 對象的標(biāo)準(zhǔn)操作方法:get、list、create、update、patch、delete、deleteCollection、watch 等;

· informer-gen: 生成監(jiān)聽 crd 對象相關(guān)事件的 informer;

· lister-gen: 生成緩存層只讀的 get、list 方法。

落地情況及后續(xù)規(guī)劃

目前 bizrq 分級配額管理方案已經(jīng)在平臺的在線業(yè)務(wù)場景全面落地,我們基于 bizrq 組件,對在線業(yè)務(wù)的 argo rollout 部署對象進(jìn)行攔截和額度校驗(yàn),結(jié)合在線業(yè)務(wù)場景中的“項(xiàng)目 - 服務(wù) - 流水線”等層級的配額管理需求,實(shí)現(xiàn)了分級配額管理界面,讓用戶可以自行管理各層級的資源配額,從而解決業(yè)務(wù)資源爭搶、減輕了平臺資源管理壓力、提高了相關(guān)問題的定位和解決效率。

后續(xù)我們將持續(xù)完善 bizrq 組件的功能,例如:

·以插件式的方式支持更多種類對象的攔截和額度校驗(yàn)(例如離線訓(xùn)練任務(wù) tfjob、有狀態(tài)部署對象 statefulset 等),從而使 bizrq 分級配額管理組件能落地到更多的離在線業(yè)務(wù)場景中;

·完善自動(dòng)擴(kuò)縮容(HPA)場景下的額度校驗(yàn)。目前我們是通過分析用戶 HPA 配置的最大副本數(shù)是否會導(dǎo)致超額,來判斷用戶配置的值是否合理,后續(xù)可以給 bizrq 增加一個(gè) validating admission webhook,通過攔截 scale 對象的方式來進(jìn)行額度校驗(yàn),從而讓校驗(yàn)邏輯更加健壯、完整。

另外,我們也會結(jié)合實(shí)際的業(yè)務(wù)場景,完善上層功能的使用體驗(yàn)。例如優(yōu)化資源額度的遷入遷出、借用流程;完善資源碎片分析、給業(yè)務(wù)推薦更加合理的部署資源套餐等能力,提升用戶資源配額管理的體驗(yàn)和效率。

審核編輯 :李倩

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • cpu
    cpu
    +關(guān)注

    關(guān)注

    68

    文章

    10908

    瀏覽量

    213109
  • AI
    AI
    +關(guān)注

    關(guān)注

    87

    文章

    31616

    瀏覽量

    270445
  • 計(jì)算平臺
    +關(guān)注

    關(guān)注

    0

    文章

    53

    瀏覽量

    9686
  • vivo
    +關(guān)注

    關(guān)注

    12

    文章

    3310

    瀏覽量

    63709
  • 深度學(xué)習(xí)
    +關(guān)注

    關(guān)注

    73

    文章

    5516

    瀏覽量

    121586

原文標(biāo)題:vivo AI 計(jì)算平臺的 K8s 分級配額管理實(shí)踐

文章出處:【微信號:AI前線,微信公眾號:AI前線】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    搭建K8s環(huán)境平臺的步驟

    1 搭建K8s環(huán)境平臺規(guī)劃1.1 單master集群1.2 多master集群
    發(fā)表于 11-04 06:03

    OpenStack與K8s結(jié)合的兩種方案的詳細(xì)介紹和比較

    OpenStack與K8S結(jié)合主要有兩種方案。一是K8S部署在OpenStack平臺之上,二是K8S和OpenStack組件集成。
    的頭像 發(fā)表于 10-14 09:38 ?2.7w次閱讀

    如何使用kubernetes client-go實(shí)踐一個(gè)簡單的與K8s交互過程

    【導(dǎo)讀】Kubernetes項(xiàng)目使用Go語言編寫,對Go api原生支持非常便捷。 本篇文章介紹了如何使用kubernetes client-go實(shí)踐一個(gè)簡單的與K8s交互過程
    的頭像 發(fā)表于 02-02 11:16 ?6936次閱讀
    如何使用kubernetes client-go<b class='flag-5'>實(shí)踐</b>一個(gè)簡單的與<b class='flag-5'>K8s</b>交互過程

    Docker不香嗎為什么還要用K8s

    Docker 雖好用,但面對強(qiáng)大的集群,成千上萬的容器,突然感覺不香了。 這時(shí)候就需要我們的主角 Kubernetes 上場了,先來了解一下 K8s 的基本概念,后面再介紹實(shí)踐,由淺入深步步為營
    的頭像 發(fā)表于 06-02 11:56 ?3498次閱讀

    簡單說明k8s和Docker之間的關(guān)系

    這篇文章主要介紹了k8s和Docker關(guān)系簡單說明,本文利用圖文講解的很透徹,有需要的同學(xué)可以研究下 最近項(xiàng)目用到kubernetes(以下簡稱k8s,ks之間有
    的頭像 發(fā)表于 06-24 15:48 ?3477次閱讀

    K8S集群服務(wù)訪問失敗怎么辦 K8S故障處理集錦

    問題1:K8S集群服務(wù)訪問失??? ? ? 原因分析:證書不能被識別,其原因?yàn)椋鹤远x證書,過期等。 解決方法:更新證書即可。 問題2:K8S集群服務(wù)訪問失敗? curl: (7) Failed
    的頭像 發(fā)表于 09-01 11:11 ?1.6w次閱讀
    <b class='flag-5'>K8S</b>集群服務(wù)訪問失敗怎么辦 <b class='flag-5'>K8S</b>故障處理集錦

    K8S(kubernetes)學(xué)習(xí)指南

    K8S(kubernetes)學(xué)習(xí)指南
    發(fā)表于 06-29 14:14 ?0次下載

    mysql部署在k8s上的實(shí)現(xiàn)方案

    的 RDBMS (Relational Database Management System,關(guān)系數(shù)據(jù)庫管理系統(tǒng)) 應(yīng)用軟件之一。這里主要講 mysql 部署在 k8s 上,mysql 部署在 k8s 上的優(yōu)勢主要有以下幾點(diǎn)。
    的頭像 發(fā)表于 09-26 10:39 ?2569次閱讀

    k8s是什么意思?kubeadm部署k8s集群(k8s部署)|PetaExpres

    k8s是什么意思? kubernetes簡稱K8s,是一個(gè)開源的,用于管理平臺中多個(gè)主機(jī)上的容器化的應(yīng)用,Kubernetes的目標(biāo)是讓部署容器化的應(yīng)用簡單并且高效(powerful
    發(fā)表于 07-19 13:14 ?1160次閱讀

    什么是K3sK8sK3sK8s有什么區(qū)別?

    Kubernetes,通??s寫為 K8s,是領(lǐng)先的容器編排工具。該開源項(xiàng)目最初由 Google 開發(fā),幫助塑造了現(xiàn)代編排的定義。該系統(tǒng)包括了部署和運(yùn)行容器化系統(tǒng)所需的一切。
    的頭像 發(fā)表于 08-03 10:53 ?7723次閱讀

    跑大模型AIK8s與普通K8s的區(qū)別分析

    Kubernetes是一個(gè)在大量節(jié)點(diǎn)上管理容器的系統(tǒng),其主要功能總結(jié)起來,就是在想要啟動(dòng)容器的時(shí)候,負(fù)責(zé)“找一個(gè)「空閑」節(jié)點(diǎn),啟動(dòng)容器”。但是它默認(rèn)考慮的啟動(dòng)因素(資源類)主要就是“CPU+內(nèi)存”。就是容器指定“我要多少CPU+多少內(nèi)存”,然后K8s找到符合這個(gè)要求的節(jié)點(diǎn)
    發(fā)表于 09-03 12:07 ?986次閱讀

    K8s多集群管理:為什么需要多集群、多集群的優(yōu)勢是什么

    隨著K8s和云原生技術(shù)的快速發(fā)展,以及各大廠商在自己的數(shù)據(jù)中心使用K8s的API進(jìn)行容器化應(yīng)用編排和管理,讓應(yīng)用交付本身變得越來越標(biāo)準(zhǔn)化和統(tǒng)一化,并且實(shí)現(xiàn)了與底層基礎(chǔ)設(shè)施的完全解耦,為多集群和混合云提供了一個(gè)堅(jiān)實(shí)技術(shù)基礎(chǔ)。
    發(fā)表于 09-14 10:48 ?1480次閱讀
    <b class='flag-5'>K8s</b>多集群<b class='flag-5'>管理</b>:為什么需要多集群、多集群的優(yōu)勢是什么

    K8S落地實(shí)踐經(jīng)驗(yàn)分享

    k8s 即 Kubernetes,是一個(gè)開源的容器編排引擎,用來對容器化應(yīng)用進(jìn)行自動(dòng)化部署、 擴(kuò)縮和管理。
    的頭像 發(fā)表于 01-02 11:45 ?1259次閱讀
    <b class='flag-5'>K8S</b>落地<b class='flag-5'>實(shí)踐</b>經(jīng)驗(yàn)分享

    k8s云原生開發(fā)要求

    IO性能。網(wǎng)絡(luò)要求穩(wěn)定,建議使用私有網(wǎng)絡(luò)VPC,并配置與Kubernetes兼容的網(wǎng)絡(luò)插件。操作系統(tǒng)需與K8s版本匹配,虛擬化平臺支持Docker等。此外,還需關(guān)注安全配置,如禁用Swap、調(diào)整Sysctl等,以及etcd數(shù)據(jù)存儲后端的配置。合理配置硬件可確保
    的頭像 發(fā)表于 10-24 10:03 ?284次閱讀
    <b class='flag-5'>k8s</b>云原生開發(fā)要求

    k8s和docker區(qū)別對比,哪個(gè)更強(qiáng)?

    Docker和Kubernetes(K8s)是容器化技術(shù)的兩大流行工具。Docker關(guān)注構(gòu)建和打包容器,適用于本地開發(fā)和單主機(jī)管理;而K8s則提供容器編排和管理
    的頭像 發(fā)表于 12-11 13:55 ?191次閱讀