Kubernetes Resource QoS Classes介绍

简介: 基本概念 Kubernetes根据Pod中Containers Resource的request和limit的值来定义Pod的QoS Class。其中,指定容器request,代表系统确保能够提供的资源下限值。

基本概念


Kubernetes根据Pod中Containers Resource的request和limit的值来定义Pod的QoS Class。其中,指定容器request,代表系统确保能够提供的资源下限值。指定容器limit,代表系统允许提供的资源上限值。

Pods需要保证长期稳定运行需要设定“确保运行的最少资源”,然而pod能够使用的资源经常是不能确保的。

通常,Kubernetes通过设置request和limit的值来指定超卖比例,进而提升资源利用率。K8S的调度基于request,而不是limit。Borg通过使用“non-guranteed”的资源,提升了20%的资源利用率。

在一个资源被“超卖”的系统(总limits > machine capacity),容器在资源被耗尽的情况下会被kill。理想情况是那些“不重要”的容器先被kill。

对于每一种Resource都可以将容器分为3中QoS Classes: Guaranteed, Burstable, and Best-Effort,它们的QoS级别依次递减。K8S底层实际上是通过 limit和request值来实现不同等级QoS的划分。

  • Guaranteed 如果Pod中所有Container的所有Resource的limit和request都相等且不为0,则这个Pod的QoS Class就是Guaranteed。

注意,如果一个容器只指明了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都没有赋值,则这个Pod的QoS Class就是Best-Effort.
Examples: containers:
 name: foo
 resources:
 name: bar
 resources:
  • Burstable 除了符合Guaranteed和Best-Effort的场景,其他场景的Pod QoS Class都属于Burstable。 当limit值未指定时,其有效值其实是对应Node Resource的Capacity。

Examples: 容器bar没有对Resource进行指定。

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

 name: bar

容器foo和bar对不同的Resource进行了指定。

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

可压缩/不可压缩资源的区别

kube-scheduler调度时,是基于Pod的request值进行Node Select完成调度的。Pod和它的所有Container都不允许Consume limit指定的有效值(if have)。

request和limit如何生效,依赖于资源是否是压缩的

可压缩资源的保证

  • 目前仅支持CPU。
  • Pods确保可以获取请求的CPU总量,但并不能获得额外的CPU时间。这并不能完全确保容器能够用到设置的资源下限值,因为CPU隔离是容器级别的。之后会引入Pod级别的cgroups资源隔离来解决这个问题。
  • 过量/竞争使用CPU资源,会基于CPU request设置。可通过cpu.share来分派不同比例的时间片来理解,如果某个容器A的request 设置为600 milli,容器B设置为300mili , 两者竞争CPU时间时,通过2:1的比例来分配。
  • 如果达到Pod CPU资源limit上限,CPU会减速(throttled),而不是kill pod。如果pod没有设置limit上限,pods可以使用超过CPU limit上限。

不可压缩资源的保证

  • 目前仅支持内存。
  • Pods可以拿到requests设置的内存总量。如果某个pod超过memory request值,当其他pod需要内存时,这个pod可能被kill掉。但是如果pods使用内存少于request值,它们不会被kill,除非系统任务或daemon需要更多资源。(说白了,还是要看触发oom killer时,遍历系统上所有进程打分的情况。)
  • 当Pods使用内存超过了limit,某个在pod中容器内进程使用了大量内存,则该进程会被内核kill掉.

管理和调度策略

如何根据不同的QoS回收Resources

  • CPU 当CPU使用不能达到request值,比如系统任务和daemons使用了大量CPU,则Pods不会被kill,CPU效率会下降(throttled)。
  • Memory 内存是不可压缩资源,从内存管理的角度做如下区分:
    • Best-Effort pods 优先级最低。如果系统内存耗尽,该类型的pods中的进程最先被kill。这些容器可以使用系统上任意量的空闲内存。
    • Guaranteed pods 优先级最高。它们能够确保不达到容器设置的limit上限一定不会被kill。只有在系统存在内存压力且没有更低优先级容器时才被驱逐。
    • Burstable pods 有一些形式的最小资源保证,但当需要时可以使用更多资源。在系统存在内存瓶颈时,一旦内存超过他们的request值并且没有Best-Effort 类型的容器存在,这些容器就先被kill掉。

Node上的OOM Score 配置

Pod OOM 打分配置

mm/oom_kill.c 中的badness()给每个进程一个OOM score,更高OOM得分的进程更容易被kill。得分取决于:

  • 主要是看进程的内存消耗情况,包括驻留内存、pagetable和swap的使用
    • 一般是内存耗费的百分比*10(percent-times-ten)
  • 参考用户权限,比如root权限启动的进程,打分会减少30。
  • OOM打分因子:/proc/pid/oom_score_adj (加减) 和 /proc/pid/oom_adj(乘除)
    • oom_adj: -15~ 15的系数调整
    • oom_score_adj:oom_score会加上oom_score_adj这个值
    • 最终oom score的值 还是在 0~1000

这里提供一个计算系统上oom_score分数TPO10进程(最容易被oom killer杀掉的进程)脚本:

# 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%的可用内存,OOM_SCORE_ADJ设置为 2。否则, OOM_SCORE_ADJ = 1000 - 10 * (% of memory requested),这确保了burstable的 POD OOM_SCORE > 1
  • 如果memory request设置为0,OOM_SCORE_ADJ 默认设置为999。所以如果burstable pods和guaranteed pods冲突时,前者会被kill。
  • 如果burstable pod使用的内存少于request值,那它的OOM_SCORE < 1000。如果best-effort pod和这些 burstable pod冲突时,best-effort pod会先被kill掉。
  • 如果 burstable pod容器中进程使用比request值的内存更多,OOM_SCORE设置为1000。反之,OOM_SCORES少于1000。
  • 在一堆burstable pod中,使用内存超过request值的pod,优先于内存使用少于request值的pod被kill。
  • 如果 burstable pod 有多个进程冲突,则OOM_SCORE会被随机设置,不受“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)
  • 系统上的关键进程,如果和guranteed 进程冲突,则会优先被kill 。将来会被放到一个单独的cgroup中,并且限制内存。

已知的issue和潜在优化点

  • 支持swap: 当前QoS策略默认swap关闭。如果开启swap,那些guaranteed 容器资源使用达到limit值,还可以使用磁盘来提供内存分配。最终,当swap空间不够时,pod中的进程才会被kill.此时,node需要在提供隔离策略时,把swap空间考虑进去。
  • 提供用户指定优先级:用户让kubelet指定哪些tasks可以被kill.

源码分析

QoS的源码位于:pkg/kubelet/qos,代码非常简单,主要就两个文件pkg/kubelet/qos/policy.go,pkg/kubelet/qos/qos.go。 上面讨论的各个QoS Class对应的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的计算方法定义在:

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会在eviction_manager和scheduler的Predicates阶段被调用,也就说会在k8s处理超配和调度预选阶段中被使用。

本文转自开源中国-Kubernetes Resource QoS Classes介绍

相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
云原生实践公开课
课程大纲 开篇:如何学习并实践云原生技术 基础篇: 5 步上手 Kubernetes 进阶篇:生产环境下的 K8s 实践 相关的阿里云产品:容器服务&nbsp;ACK 容器服务&nbsp;Kubernetes&nbsp;版(简称&nbsp;ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情:&nbsp;https://www.aliyun.com/product/kubernetes
相关文章
|
7月前
|
Kubernetes 网络性能优化 调度
聊聊 K8S pod 的 QoS(Quality Of Service)
聊聊 K8S pod 的 QoS(Quality Of Service)
|
运维 Kubernetes 网络性能优化
关于K8s中资源服务质量管理Resource Qos(超售超用)的一些笔记
写在前面 分享一些 K8s中资源服务质量管理Resource Qos 的笔记 博文内容涉及: K8s Qos 简单介绍 资源配置的特点: 节点的超用,可压缩/不可压缩,完全可靠性等介绍 QoS Classes 介绍 三种 Qos 服务质量等级 Pod 定义的 Demo 理解不足小伙伴帮忙指正
551 0
|
Kubernetes 网络性能优化 调度
图解 K8S 源码 - QoS 篇
图解 K8S 中 QoS 源码,了解 QoS 分类、打分机制以及其本质
2965 0
|
Kubernetes 大数据 测试技术
容器开启数据服务之旅系列(四):Kubernetes QoS 助力在线运用与大数据离线运用的带宽控制和磁盘控制
本文是2018年大数据峰会上的一些分享,关于在线业务,离线业务在ACK(阿里云容器服务Kubernetes)的平台上通过对bandwidth, disk quota的灵活组合完成在线,离线业务场景的混合部署,来提高总体资源的使用率,以及带宽,本地盘资源的动态分配调整,来控制离线,在线资源水位。
2618 0
|
Kubernetes 大数据 网络性能优化
容器开启数据服务之旅系列(三):Kubernetes QoS助力在线运用与大数据离线运用的混部
本文是2018年大数据峰会上的一些分享,关于在线业务,离线业务在ACK(阿里云容器服务Kubernetes)的平台上通过对namespace, cgroup, quota的灵活组合完成在线,离线业务场景的混合部署,来提高总体资源的使用率,以及支资源限制动态分配调整,来伸缩离线部分的资源水位。
1675 0
|
1天前
|
Kubernetes 安全 API
Kubernetes学习-集群搭建篇(三) Node配置完善和API概述
Kubernetes学习-集群搭建篇(三) Node配置完善和API概述
Kubernetes学习-集群搭建篇(三) Node配置完善和API概述
|
1天前
|
Kubernetes 应用服务中间件 Docker
Kubernetes学习-集群搭建篇(二) 部署Node服务,启动JNI网络插件
Kubernetes学习-集群搭建篇(二) 部署Node服务,启动JNI网络插件
|
1天前
|
存储 运维 Kubernetes
Kubernetes学习-集群搭建篇(一) 搭建Master结点
Kubernetes学习-集群搭建篇(一) 搭建Master结点
|
1天前
|
Kubernetes API 调度
Kubernetes学习-核心概念篇(二) 集群架构与组件
Kubernetes学习-核心概念篇(二) 集群架构与组件
|
3天前
|
存储 运维 监控
Kubernetes 集群的持续监控与性能优化策略
【5月更文挑战第11天】在微服务架构日益普及的当下,Kubernetes 已成为容器编排的事实标准。随着其在不同规模企业的广泛采用,如何确保 Kubernetes 集群的高效稳定运行变得至关重要。本文将探讨一套系统的 Kubernetes 集群监控方法,并结合实践经验分享针对性能瓶颈的优化策略。通过实时监控、日志分析与定期审计的结合,旨在帮助运维人员快速定位问题并提出解决方案,从而提升系统的整体表现。