你真的理解 Kubernetes 中的 requests 和 limits 吗?

2023年 7月 9日 39.8k 0

在 Kubernetes 集群中部署资源的时候,你是否经常遇到以下情形:

  • 经常在 Kubernetes 集群种部署负载的时候不设置 CPU requests 或将 CPU requests 设置得过低(这样“看上去”就可以在每个节点上容纳更多 Pod )。在业务比较繁忙的时候,节点的 CPU 全负荷运行。业务延迟明显增加,有时甚至机器会莫名其妙地进入 CPU 软死锁等“假死”状态。
  • 类似地,部署负载的时候,不设置内存 requests 或者内存 requests 设置得过低,这时会发现有些 Pod 会不断地失败重启。而不断重启的这些 Pod 通常跑的是 Java 业务应用。但是这些 Java 应用本地调试运行地时候明明都是正常的。
  • 在 Kubernetes 集群中,集群负载并不是完全均匀地在节点间分配的,通常内存不均匀分配的情况较为突出,集群中某些节点的内存使用率明显高于其他节点。Kubernetes 作为一个众所周知的云原生分布式容器编排系统,一个所谓的事实上标准,其调度器不是应该保证资源的均匀分配吗?
  • 如果在业务高峰时间遇到上述问题,并且机器已经 hang 住甚至无法远程 ssh 登陆,那么通常留给集群管理员的只剩下重启集群这一个选项。

    如果你遇到过上面类似的情形,想了解如何规避相关问题或者你是 Kubernetes 运维开发人员,想对这类问题的本质一探究竟,那么请耐心阅读下面的章节。

    我们会先对这类问题做一个定性分析,并给出避免此类问题的最佳实践,最后如果你对 Kubernetes requests 和 limits 的底层机制感兴趣,我们可以从源码角度做进一步地分析,做到“知其然也知其所以然”。

    问题分析

  • 对于情形 1首先我们需要知道对于 CPU 和内存这 2 类资源,他们是有一定区别的。 CPU 属于可压缩资源,其中 CPU 资源的分配和管理是 Linux 内核借助于完全公平调度算法( CFS )和 Cgroup 机制共同完成的。简单地讲,如果 Pod 中服务使用 CPU 超过设置的 CPU limits, Pod 的 CPU 资源会被限流( throttled )。对于没有设置limit的 Pod ,一旦节点的空闲 CPU 资源耗尽,之前分配的 CPU 资源会逐渐减少。

    不管是上面的哪种情况,最终的结果都是 Pod 已经越来越无法承载外部更多的请求,表现为应用延时增加,响应变慢。

  • 对于情形 2内存属于不可压缩资源, Pod 之间是无法共享的,完全独占的,这也就意味着资源一旦耗尽或者不足,分配新的资源一定是会失败的。有的 Pod 内部进程在初始化启动时会提前开辟出一段内存空间。比如 JVM 虚拟机在启动的时候会申请一段内存空间。如果内存 requests 指定的数值小于 JVM 虚拟机向系统申请的内存,导致内存申请失败( oom-kill ),从而 Pod 出现不断地失败重启。
  • 对于情形 3实际上在创建 Pod 的过程中,一方面, Kubernetes 需要拨备包含 CPU 和内存在内的多种资源,这里的资源均衡是包含 CPU 和内存在内的所有资源的综合考量。另一方面, Kubernetes 内置的调度算法不仅仅涉及到“最小资源分配节点”,还会把其他诸如 Pod 亲和性等因素考虑在内。并且 Kubernetes 调度基于的是资源的 requests 数值,而之所以往往观察到的是内存分布不够均衡,是因为对于应用来说,相比于其他资源,内存一般是更紧缺的一类资源。

    Kubernetes 的调度机制是基于当前的状态。比如当出现新的 Pod 进行调度时,调度程序会根据其当时对 Kubernetes 集群的资源描述做出最佳调度决定。

    但是 Kubernetes 集群是非常动态的。比如一个节点为了维护,我们先执行了驱逐操作,这个节点上的所有 Pod 会被驱逐到其他节点去,当我们维护完成后,之前的 Pod 并不会自动回到该节点上来,因为 Pod 一旦被绑定了节点是不会触发重新调度的。

  • 最佳实践

    由上面的分析我们可以看到,集群的稳定性直接决定了其上运行的业务应用的稳定性。而临时性的资源短缺往往是导致集群不稳定的主要因素。集群一旦不稳定,轻则业务应用的性能下降,重则出现相关结点不可用。

    那么如何提高集群的稳定性呢?

    一方面,可以通过编辑 Kubelet 配置文件来预留一部分系统资源,从而保证当可用计算资源较少时 kubelet 所在节点的稳定性。这在处理如内存和硬盘之类的不可压缩资源时尤为重要。

    另一方面,通过合理地设置 Pod 的 QoS 可以进一步提高集群稳定性:不同 QoS 的 Pod 具有不同的 OOM 分数,当出现资源不足时,集群会优先 Kill 掉 Best-Effort 类型的 Pod ,其次是 Burstable 类型的 Pod ,最后是Guaranteed 类型的 Pod 。

    因此,如果资源充足,可将 QoS pods 类型均设置为 Guaranteed 。用计算资源换业务性能和稳定性,减少排查问题时间和成本。同时如果想更好的提高资源利用率,业务服务也可以设置为 Guaranteed ,而其他服务根据重要程度可分别设置为 Burstable 或 Best-Effort 。

    下面我们会以 Kubesphere 平台为例,演示如何方便优雅地配置 Pod 相关的资源。

    KubeSphere 资源配置实践

    前面我们已经了解到 Kubernetes 中requestslimits这 2 个参数的合理设置对整个集群的稳定性至关重要。而作为 Kubernetes 的发行版,KubeSphere 极大地降低了 Kubernetes 的学习门槛,配合简洁美观的 UI 界面,你会发现有效运维原来是一件如此轻松的事情。下面我们将演示如何在 KubeSphere 平台中配置容器的相关资源配额与限制。

    相关概念

    在进行演示之前,让我们再回顾一下 Kubernetes 相关概念。

    requests 与 limits 简介

    为了实现 Kubernetes 集群中资源的有效调度和充分利用, Kubernetes 采用requestslimits两种限制类型来对资源进行容器粒度的分配。每一个容器都可以独立地设定相应的requestslimits。这 2 个参数是通过每个容器 containerSpec 的 resources 字段进行设置的。一般来说,在调度的时候requests比较重要,在运行时limits比较重要。

    resources:  
        requests:    
            cpu: 50m
            memory: 50Mi
       limits:    
            cpu: 100m
            memory: 100Mi
    

    requests定义了对应容器需要的最小资源量。这句话的含义是,举例来讲,比如对于一个 Spring Boot 业务容器,这里的requests必须是容器镜像中 JVM 虚拟机需要占用的最少资源。如果这里把 Pod 的内存requests指定为 10Mi ,显然是不合理的,JVM 实际占用的内存 Xms 超出了 Kubernetes 分配给 Pod 的内存,导致 Pod 内存溢出,从而 Kubernetes 不断重启 Pod 。

    limits定义了这个容器最大可以消耗的资源上限,防止过量消耗资源导致资源短缺甚至宕机。特别的,设置为 0 表示对使用的资源不做限制。值得一提的是,当设置limits而没有设置requests时,Kubernetes 默认令requests等于limits

    进一步可以把requestslimits描述的资源分为 2 类:可压缩资源(例如 CPU )和不可压缩资源(例如内存)。合理地设置limits参数对于不可压缩资源来讲尤为重要。

    前面我们已经知道requests参数会对最终的 Kubernetes 调度结果起到直接的显而易见的影响。借助于 Linux 内核 Cgroup 机制,limits参数实际上是被 Kubernetes 用来约束分配给进程的资源。对于内存参数而言,实际上就是告诉 Linux 内核什么时候相关容器进程可以为了清理空间而被杀死( oom-kill )。

    总结一下:

    • 对于 CPU,如果 Pod 中服务使用 CPU 超过设置的limits,Pod 不会被 kill 掉但会被限制。如果没有设置 limits ,pod 可以使用全部空闲的 CPU 资源。
    • 对于内存,当一个 Pod 使用内存超过了设置的limits,Pod 中 container 的进程会被 kernel 因 OOM kill 掉。当 container 因为 OOM 被 kill 掉时,系统倾向于在其原所在的机器上重启该 container 或本机或其他重新创建一个 Pod。
    • 0

    相关文章

    KubeSphere 部署向量数据库 Milvus 实战指南
    探索 Kubernetes 持久化存储之 Longhorn 初窥门径
    征服 Docker 镜像访问限制!KubeSphere v3.4.1 成功部署全攻略
    那些年在 Terraform 上吃到的糖和踩过的坑
    无需 Kubernetes 测试 Kubernetes 网络实现
    Kubernetes v1.31 中的移除和主要变更

    发布评论