kube-batch 具體如何實(shí)現(xiàn)gang scheduler

gang scheduler介紹:一個(gè)job,可能有多個(gè)tasks,這些tasks要不全部執(zhí)行,要不一個(gè)都不執(zhí)行。

上面說(shuō)到 kube-batch自定義了一個(gè)podGroup,調(diào)度時(shí)以podGroup為單位的?,F(xiàn)在說(shuō)一下調(diào)度podGroup的整個(gè)過(guò)程。

本文分為四個(gè)部分:
一:介紹kube-batch的基本概念
二:總結(jié)這些概念的關(guān)系,已經(jīng)列出可能的疑問(wèn)
三:介紹如何實(shí)現(xiàn)gang scheduler
四:總結(jié)gang scheduler的實(shí)現(xiàn)流程

第一二部分是為了幫助理解,第四部分是從代碼角度深入理解。想大概了解的,看到第三部分就可以了。

一:介紹kube-batch的基本概念:queue, podgroup, job。

(1) queue
這個(gè)一個(gè)全局的概念,意思就是沒(méi)有Namespace的這一說(shuō)法。用這個(gè)概念的目的是為了實(shí)現(xiàn)多租戶。這里一個(gè)租戶就是一個(gè)隊(duì)列。kube-batch默認(rèn)有一個(gè)default-queue。如果用戶創(chuàng)建的任務(wù)沒(méi)有指定隊(duì)列,都會(huì)放在默認(rèn)的這個(gè)隊(duì)列里。

type QueueInfo struct {
    UID  QueueID
    Name string
    Weight int32
    Queue *arbcorev1.Queue
}

查看 queue 的定義,發(fā)現(xiàn)這里有個(gè) Weight的屬性。這個(gè)干什么用的呢?
繼續(xù)往下。

proportion.go:116

// Calculates the deserved of each Queue.
        deserved := api.EmptyResource()
        for _, attr := range pp.queueOpts {
            glog.V(4).Infof("Considering Queue <%s>: weight <%d>, total weight <%d>.",
                attr.name, attr.weight, totalWeight)
            if _, found := meet[attr.queueID]; found {
                continue
            }

            attr.deserved.Add(remaining.Clone().Multi(float64(attr.weight) / float64(totalWeight)))
            if !attr.deserved.LessEqual(attr.request) {
                attr.deserved = helpers.Min(attr.deserved, attr.request)
                meet[attr.queueID] = struct{}{}
            }
            pp.updateShare(attr)

            glog.V(4).Infof("The attributes of queue <%s> in proportion: deserved <%v>, allocate <%v>, request <%v>, share <%0.2f>",
                attr.name, attr.deserved, attr.allocated, attr.request, attr.share)

            deserved.Add(attr.deserved)
        }

可以看出來(lái),"Weight" 是分配資源用的。一個(gè)Queue代表一個(gè)租戶,它們按照權(quán)重分配集群的資源。下面這個(gè)圖清晰明了:


image.png

(2)job
這里很容易弄混,kube-batch的job 和 k8s的job是不一樣的。

type JobInfo struct {
    UID JobID
    Name      string
    Namespace string
    Queue QueueID
    Priority int32
    NodeSelector map[string]string
    MinAvailable int32
    NodesFitDelta NodeResourceMap
    // All tasks of the Job.
    TaskStatusIndex map[TaskStatus]tasksMap
    Tasks           tasksMap
    Allocated    *Resource
    TotalRequest *Resource
    CreationTimestamp metav1.Time
    PodGroup          *v1alpha1.PodGroup
    // TODO(k82cn): keep backward compatibility, removed it when v1alpha1 finalized.
    PDB *policyv1.PodDisruptionBudget
}

這是kube-batch 中job的定義,這里要理解成: kube-batch job是一堆Task的集合(1個(gè)Task是一個(gè)pod)。
這里的job和K8s中job的區(qū)別是:
如果有一個(gè)k8s的job, 假設(shè)為Job1,有2個(gè)pod, 他指定的podgroup是gp1.
同時(shí)還有一個(gè)k8s的job, 假設(shè)為Job2,有2個(gè)pod, 他指定的podgroup也是gp1.

如果同時(shí)提交這倆個(gè)k8s job。那么在kube-batch看來(lái),當(dāng)前要調(diào)度的只有一個(gè)"job"(這是kube-batch的一個(gè)作業(yè))。這個(gè)kube-batch job總共有4個(gè)Tasks(pod)需要綁定。

所以,kube-batch的job,它是指向某個(gè)podgroup 所有的k8s job的pod集合。
有點(diǎn)拗口,結(jié)合上面例子再讀讀。

(3) podgroup
我原本以為一個(gè)podgroup對(duì)應(yīng)的是一個(gè)k8s job。后面我發(fā)現(xiàn):
a. 我運(yùn)行一個(gè)job不指定podgroup也能正常運(yùn)行。
b. 我同時(shí)運(yùn)行倆個(gè)job,指定的是同一個(gè)podgroup也能正常運(yùn)行。

所以,我就非常奇怪,看了相關(guān)源碼后發(fā)現(xiàn),這里的podgroup是一個(gè)pod的集合。
如果有n個(gè)k8s job指向他,那么他就是這個(gè)n個(gè)Job的所有pod的集合。

二:總結(jié)這些概念的關(guān)系

(1)提交每個(gè)k8s job都必須指定一個(gè)podgroup
Q: 為什么創(chuàng)建job時(shí),不指定也能運(yùn)行?
A: kube-batch會(huì)為這類(lèi)job,創(chuàng)建一個(gè) shadow PodGroup

(2)一個(gè)podGroup對(duì)應(yīng)一個(gè)queue
Q:為什么創(chuàng)建queue時(shí),不指定也能運(yùn)行
A:不指定,默認(rèn)使用default-queue

(3)一個(gè)kube-batch中的job 包含podgroup中所有的pod.
(4)這個(gè)kube-batch的job使用 queue中的資源,完成task

三:介紹如何實(shí)現(xiàn)gang scheduler

結(jié)合圖片和文字一起看,能加深理解


image.png

這里以倆個(gè)k8s job為例介紹這個(gè)過(guò)程
(1)將指向某個(gè)podgroup的 所有k8s job中的pod合在一起生成一個(gè) kube-batch job. (比如上面圖中,最后kube-batch job的Tasks是 n1+n2)
(2) 開(kāi)始調(diào)度kube-batch中的job
(3) 每次完成一個(gè)task(這里是假裝綁定一個(gè)pod),當(dāng)完成的task數(shù)量 達(dá)到MIN(podgroup設(shè)定的值)時(shí),開(kāi)始真正的綁定,一次性綁定MIN個(gè)task。然后將剩下的Tasks 生成一個(gè)新的kube-batch job 再次調(diào)度。如果在沒(méi)達(dá)到MIN 個(gè)之前,已經(jīng)資源不足,那么進(jìn)入backfill 操作,釋放之前綁定的job。

所以實(shí)現(xiàn)gang scheduler的關(guān)鍵還是 podgroup,通過(guò)設(shè)置podgroup的minNumber。達(dá)到每次調(diào)度要么 執(zhí)行minNumber個(gè)tasks.要么一個(gè)都不執(zhí)行。

PS:
上面的圖片是為了解釋, 所以放了倆個(gè)k8s job.
如果想讓這倆個(gè)job進(jìn)行g(shù)ang scheduer, 直接令 minNumber = n1+n2.
這樣倆個(gè)job就會(huì)同時(shí)執(zhí)行。

四:總結(jié)gang scheduler的實(shí)現(xiàn)流程

我一開(kāi)始非常納悶為什么podgroup不是和k8s job一一對(duì)應(yīng)。后面我仔細(xì)想想,發(fā)現(xiàn)這樣設(shè)計(jì),更加靈活。
如果是k8s job和podgroup一一對(duì)應(yīng)的話。那么podgroup包含的就是這個(gè)k8s job的所有pod.這樣每次就只能對(duì)一個(gè)k8s job進(jìn)行g(shù)ang scheduler.

而他這樣設(shè)計(jì),則同時(shí)進(jìn)行一個(gè)或者多個(gè)K8s job的調(diào)度。
(通過(guò)調(diào)整n1,n2以及minNumber的值)

注意:
這樣也可能產(chǎn)生不好的影響。
例如我有兩個(gè)K8s job.描述如下:
job1 需要6個(gè)pod,1個(gè)pod需要1個(gè)cpu
job2 需要6個(gè)pod,1個(gè)pod需要100個(gè)cpu
現(xiàn)在集群總共有6個(gè)cpu.
如果我不小心,將job1,job2的podgroup設(shè)置成一樣。那么這次就會(huì)出現(xiàn)死鎖,這倆個(gè)job都不會(huì)執(zhí)行。

原因:
此時(shí)只有一個(gè)kube-batch的job,并且Tasks隊(duì)列很有可能為:
job1-pod1, job2-pod1,job1-pod1......

這樣當(dāng)創(chuàng)建到j(luò)ob2-pod1, 這個(gè)任務(wù)時(shí),已經(jīng)資源不足了。然后釋放資源,重新再來(lái)。這樣就會(huì)一直死循環(huán)。

所以,要靈活使用Podgroup.

本來(lái)想再加一個(gè)步驟:“從代碼中找出gang scheduler這個(gè)過(guò)程"
由于篇幅和時(shí)間的原因,下篇文章在介紹。
從代碼角度查找,能理解更多的細(xì)節(jié)。
比如有多個(gè)隊(duì)列,每個(gè)隊(duì)列有多個(gè)任務(wù),那么kubu-batch首先運(yùn)行哪個(gè)呢?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容