溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Kubernetes Resource QoS Classes概念是什么

發(fā)布時(shí)間:2022-01-11 17:57:41 來源:億速云 閱讀:169 作者:iii 欄目:云計(jì)算

本文小編為大家詳細(xì)介紹“Kubernetes Resource QoS Classes概念是什么”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“Kubernetes Resource QoS Classes概念是什么”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學(xué)習(xí)新知識(shí)吧。

Kubernetes Resource QoS Classes介紹

基本概念

Kubernetes根據(jù)Pod中Containers Resource的request和limit的值來定義Pod的QoS Class。其中,指定容器request,代表系統(tǒng)確保能夠提供的資源下限值。指定容器limit,代表系統(tǒng)允許提供的資源上限值。

Pods需要保證長期穩(wěn)定運(yùn)行需要設(shè)定“確保運(yùn)行的最少資源”,然而pod能夠使用的資源經(jīng)常是不能確保的。

通常,Kubernetes通過設(shè)置request和limit的值來指定超賣比例,進(jìn)而提升資源利用率。K8S的調(diào)度基于request,而不是limit。Borg通過使用“non-guranteed”的資源,提升了20%的資源利用率。

在一個(gè)資源被“超賣”的系統(tǒng)(總limits > machine capacity),容器在資源被耗盡的情況下會(huì)被kill。理想情況是那些“不重要”的容器先被kill。

對于每一種Resource都可以將容器分為3中QoS Classes: Guaranteed, Burstable, and Best-Effort,它們的QoS級別依次遞減。K8S底層實(shí)際上是通過 limit和request值來實(shí)現(xiàn)不同等級QoS的劃分。

  • Guaranteed 如果Pod中所有Container的所有Resource的limit和request都相等且不為0,則這個(gè)Pod的QoS Class就是Guaranteed。

注意,如果一個(gè)容器只指明了limit,而未指明request,則表明request的值等于limit的值。

Examples:
containers:
    name: foo
        resources:
            limits:
                cpu: 10m
                memory: 1Gi
    name: bar
        resources:
            limits:
                cpu: 100m
                memory: 100Mi
containers:
    name: foo
        resources:
            limits:
                cpu: 10m
                memory: 1Gi
            requests:
                cpu: 10m
                memory: 1Gi

    name: bar
        resources:
            limits:
                cpu: 100m
                memory: 100Mi
            requests:
                cpu: 100m
                memory: 100Mi
  • Best-Effort 如果Pod中所有容器的所有Resource的request和limit都沒有賦值,則這個(gè)Pod的QoS Class就是Best-Effort.

Examples:
containers:
    name: foo
        resources:
    name: bar
        resources:
  • Burstable 除了符合Guaranteed和Best-Effort的場景,其他場景的Pod QoS Class都屬于Burstable。 當(dāng)limit值未指定時(shí),其有效值其實(shí)是對應(yīng)Node Resource的Capacity。

Examples: 容器bar沒有對Resource進(jìn)行指定。

containers:
    name: foo
        resources:
            limits:
                cpu: 10m
                memory: 1Gi
            requests:
                cpu: 10m
                memory: 1Gi

    name: bar

容器foo和bar對不同的Resource進(jìn)行了指定。

containers:
    name: foo
        resources:
            limits:
                memory: 1Gi

    name: bar
        resources:
            limits:
                cpu: 100m

容器foo未指定limit,容器bar未指定request和limit。

containers:
    name: foo
        resources:
            requests:
                cpu: 10m
                memory: 1Gi

    name: bar

可壓縮/不可壓縮資源的區(qū)別

kube-scheduler調(diào)度時(shí),是基于Pod的request值進(jìn)行Node Select完成調(diào)度的。Pod和它的所有Container都不允許Consume limit指定的有效值(if have)。

request和limit如何生效,依賴于資源是否是壓縮的

可壓縮資源的保證
  • 目前僅支持CPU。

  • Pods確保可以獲取請求的CPU總量,但并不能獲得額外的CPU時(shí)間。這并不能完全確保容器能夠用到設(shè)置的資源下限值,因?yàn)镃PU隔離是容器級別的。之后會(huì)引入Pod級別的cgroups資源隔離來解決這個(gè)問題。

  • 過量/競爭使用CPU資源,會(huì)基于CPU request設(shè)置??赏ㄟ^cpu.share來分派不同比例的時(shí)間片來理解,如果某個(gè)容器A的request 設(shè)置為600 milli,容器B設(shè)置為300mili , 兩者競爭CPU時(shí)間時(shí),通過2:1的比例來分配。

  • 如果達(dá)到Pod CPU資源limit上限,CPU會(huì)減速(throttled),而不是kill pod。如果pod沒有設(shè)置limit上限,pods可以使用超過CPU limit上限。

不可壓縮資源的保證
  • 目前僅支持內(nèi)存。

  • Pods可以拿到requests設(shè)置的內(nèi)存總量。如果某個(gè)pod超過memory request值,當(dāng)其他pod需要內(nèi)存時(shí),這個(gè)pod可能被kill掉。但是如果pods使用內(nèi)存少于request值,它們不會(huì)被kill,除非系統(tǒng)任務(wù)或daemon需要更多資源。(說白了,還是要看觸發(fā)oom killer時(shí),遍歷系統(tǒng)上所有進(jìn)程打分的情況。)

  • 當(dāng)Pods使用內(nèi)存超過了limit,某個(gè)在pod中容器內(nèi)進(jìn)程使用了大量內(nèi)存,則該進(jìn)程會(huì)被內(nèi)核kill掉.

管理和調(diào)度策略
  • Pods由kubelet 確認(rèn)和 scheduler 調(diào)度,會(huì)基于分配給容器的requests值,確保所有容器的requests總量在Node可分配容量的范圍之內(nèi)。https://github.com/fabric8io/jenkinshift/blob/master/vendor/k8s.io/kubernetes/docs/proposals/node-allocatable.md

如何根據(jù)不同的QoS回收Resources

  • CPU 當(dāng)CPU使用不能達(dá)到request值,比如系統(tǒng)任務(wù)和daemons使用了大量CPU,則Pods不會(huì)被kill,CPU效率會(huì)下降(throttled)。

  • Memory 內(nèi)存是不可壓縮資源,從內(nèi)存管理的角度做如下區(qū)分:

    • Best-Effort pods 優(yōu)先級最低。如果系統(tǒng)內(nèi)存耗盡,該類型的pods中的進(jìn)程最先被kill。這些容器可以使用系統(tǒng)上任意量的空閑內(nèi)存。

    • Guaranteed pods 優(yōu)先級最高。它們能夠確保不達(dá)到容器設(shè)置的limit上限一定不會(huì)被kill。只有在系統(tǒng)存在內(nèi)存壓力且沒有更低優(yōu)先級容器時(shí)才被驅(qū)逐。

    • Burstable pods 有一些形式的最小資源保證,但當(dāng)需要時(shí)可以使用更多資源。在系統(tǒng)存在內(nèi)存瓶頸時(shí),一旦內(nèi)存超過他們的request值并且沒有Best-Effort 類型的容器存在,這些容器就先被kill掉。

Node上的OOM Score 配置

Pod OOM 打分配置

mm/oom_kill.c 中的badness()給每個(gè)進(jìn)程一個(gè)OOM score,更高OOM得分的進(jìn)程更容易被kill。得分取決于:

  • 主要是看進(jìn)程的內(nèi)存消耗情況,包括駐留內(nèi)存、pagetable和swap的使用

    • 一般是內(nèi)存耗費(fèi)的百分比*10(percent-times-ten)

  • 參考用戶權(quán)限,比如root權(quán)限啟動(dòng)的進(jìn)程,打分會(huì)減少30。

  • OOM打分因子:/proc/pid/oom_score_adj (加減) 和 /proc/pid/oom_adj(乘除)

    • oom_adj: -15~ 15的系數(shù)調(diào)整

    • oom_score_adj:oom_score會(huì)加上oom_score_adj這個(gè)值

    • 最終oom score的值 還是在 0~1000

這里提供一個(gè)計(jì)算系統(tǒng)上oom_score分?jǐn)?shù)TPO10進(jìn)程(最容易被oom killer殺掉的進(jìn)程)腳本:

# vim oomscore.sh
#!/bin/bash
for proc in $(find /proc -maxdepth 1 -regex '/proc/[0-9]+'); do
        printf "%2d %5d %s\n" \
                "$(cat $proc/oom_score)" \
                "$(basename $proc)" \
                "$(cat $proc/cmdline | tr '\0' ' ' | head -c 50)"
done 2>/dev/null | sort -nr | head -n 10

以下是幾種K8S QoS 等級的OOM score:

Best-effort
  • Set OOM_SCORE_ADJ: 1000

  • 所以best-effort容器的OOM_SCORE 值為1000

Guaranteed
  • Set OOM_SCORE_ADJ: -998

  • 所以guaranteed容器的OOM_SCORE 值為0 或 1

Burstable
  • 如果總的memory request 大于 99.9%的可用內(nèi)存,OOM_SCORE_ADJ設(shè)置為 2。否則, OOM_SCORE_ADJ = 1000 - 10 * (% of memory requested),這確保了burstable的 POD OOM_SCORE > 1

  • 如果memory request設(shè)置為0,OOM_SCORE_ADJ 默認(rèn)設(shè)置為999。所以如果burstable pods和guaranteed pods沖突時(shí),前者會(huì)被kill。

  • 如果burstable pod使用的內(nèi)存少于request值,那它的OOM_SCORE < 1000。如果best-effort pod和這些 burstable pod沖突時(shí),best-effort pod會(huì)先被kill掉。

  • 如果 burstable pod容器中進(jìn)程使用比request值的內(nèi)存更多,OOM_SCORE設(shè)置為1000。反之,OOM_SCORES少于1000。

  • 在一堆burstable pod中,使用內(nèi)存超過request值的pod,優(yōu)先于內(nèi)存使用少于request值的pod被kill。

  • 如果 burstable pod 有多個(gè)進(jìn)程沖突,則OOM_SCORE會(huì)被隨機(jī)設(shè)置,不受“request & limit”限制。

Pod infra containers or Special Pod init process
  • OOM_SCORE_ADJ: -998

Kubelet, Docker
  • OOM_SCORE_ADJ: -999 (won’t be OOM killed)

  • 系統(tǒng)上的關(guān)鍵進(jìn)程,如果和guranteed 進(jìn)程沖突,則會(huì)優(yōu)先被kill 。將來會(huì)被放到一個(gè)單獨(dú)的cgroup中,并且限制內(nèi)存。

已知的issue和潛在優(yōu)化點(diǎn)

  • 支持swap: 當(dāng)前QoS策略默認(rèn)swap關(guān)閉。如果開啟swap,那些guaranteed 容器資源使用達(dá)到limit值,還可以使用磁盤來提供內(nèi)存分配。最終,當(dāng)swap空間不夠時(shí),pod中的進(jìn)程才會(huì)被kill.此時(shí),node需要在提供隔離策略時(shí),把swap空間考慮進(jìn)去。

  • 提供用戶指定優(yōu)先級:用戶讓kubelet指定哪些tasks可以被kill.

源碼分析

QoS的源碼位于:pkg/kubelet/qos,代碼非常簡單,主要就兩個(gè)文件pkg/kubelet/qos/policy.go,pkg/kubelet/qos/qos.go。 上面討論的各個(gè)QoS Class對應(yīng)的OOM_SCORE_ADJ定義在:

pkg/kubelet/qos/policy.go:21

const (
        PodInfraOOMAdj        int = -998
        KubeletOOMScoreAdj    int = -999
        DockerOOMScoreAdj     int = -999
        KubeProxyOOMScoreAdj  int = -999
        guaranteedOOMScoreAdj int = -998
        besteffortOOMScoreAdj int = 1000
)

容器的OOM_SCORE_ADJ的計(jì)算方法定義在:

pkg/kubelet/qos/policy.go:40

func GetContainerOOMScoreAdjust(pod *v1.Pod, container *v1.Container, memoryCapacity int64) int {
        switch GetPodQOS(pod) {
        case Guaranteed:
                // Guaranteed containers should be the last to get killed.
                return guaranteedOOMScoreAdj
        case BestEffort:
                return besteffortOOMScoreAdj
        }

        // Burstable containers are a middle tier, between Guaranteed and Best-Effort. Ideally,
        // we want to protect Burstable containers that consume less memory than requested.
        // The formula below is a heuristic. A container requesting for 10% of a system's
        // memory will have an OOM score adjust of 900. If a process in container Y
        // uses over 10% of memory, its OOM score will be 1000. The idea is that containers
        // which use more than their request will have an OOM score of 1000 and will be prime
        // targets for OOM kills.
        // Note that this is a heuristic, it won't work if a container has many small processes.
        memoryRequest := container.Resources.Requests.Memory().Value()
        oomScoreAdjust := 1000 - (1000*memoryRequest)/memoryCapacity
        // A guaranteed pod using 100% of memory can have an OOM score of 10. Ensure
        // that burstable pods have a higher OOM score adjustment.
        if int(oomScoreAdjust) < (1000 + guaranteedOOMScoreAdj) {
                return (1000 + guaranteedOOMScoreAdj)
        }
        // Give burstable pods a higher chance of survival over besteffort pods.
        if int(oomScoreAdjust) == besteffortOOMScoreAdj {
                return int(oomScoreAdjust - 1)
        }
        return int(oomScoreAdjust)
}

獲取Pod的QoS Class的方法為:

pkg/kubelet/qos/qos.go:50

// GetPodQOS returns the QoS class of a pod.
// A pod is besteffort if none of its containers have specified any requests or limits.
// A pod is guaranteed only when requests and limits are specified for all the containers and they are equal.
// A pod is burstable if limits and requests do not match across all containers.
func GetPodQOS(pod *v1.Pod) QOSClass {
        requests := v1.ResourceList{}
        limits := v1.ResourceList{}
        zeroQuantity := resource.MustParse("0")
        isGuaranteed := true
        for _, container := range pod.Spec.Containers {
                // process requests
                for name, quantity := range container.Resources.Requests {
                        if !supportedQoSComputeResources.Has(string(name)) {
                                continue
                        }
                        if quantity.Cmp(zeroQuantity) == 1 {
                                delta := quantity.Copy()
                                if _, exists := requests[name]; !exists {
                                        requests[name] = *delta
                                } else {
                                        delta.Add(requests[name])
                                        requests[name] = *delta
                                }
                        }
                }
                // process limits
                qosLimitsFound := sets.NewString()
                for name, quantity := range container.Resources.Limits {
                        if !supportedQoSComputeResources.Has(string(name)) {
                                continue
                        }
                        if quantity.Cmp(zeroQuantity) == 1 {
                                qosLimitsFound.Insert(string(name))
                                delta := quantity.Copy()
                                if _, exists := limits[name]; !exists {
                                        limits[name] = *delta
                                } else {
                                        delta.Add(limits[name])
                                        limits[name] = *delta
                                }
                        }
                }

                if len(qosLimitsFound) != len(supportedQoSComputeResources) {
                        isGuaranteed = false
                }
        }
        if len(requests) == 0 && len(limits) == 0 {
                return BestEffort
        }
        // Check is requests match limits for all resources.
        if isGuaranteed {
                for name, req := range requests {
                        if lim, exists := limits[name]; !exists || lim.Cmp(req) != 0 {
                                isGuaranteed = false
                                break
                        }
                }
        }
        if isGuaranteed &&
                len(requests) == len(limits) {
                return Guaranteed
        }
        return Burstable
}

PodQoS會(huì)在eviction_manager和scheduler的Predicates階段被調(diào)用,也就說會(huì)在k8s處理超配和調(diào)度預(yù)選階段中被使用。

讀到這里,這篇“Kubernetes Resource QoS Classes概念是什么”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識(shí)點(diǎn)還需要大家自己動(dòng)手實(shí)踐使用過才能領(lǐng)會(huì),如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI