一文搞懂Kubernetes的Memory和CPU 限流

前言

在使用Kubernetes时,内存不足(OOM)错误和CPU限制是云应用程序中资源处理的主要问题。为什么会这样呢?

云应用程序中的CPU和内存需求越来越重要,因为它们与云成本直接相关。

通过Limits和Request,我们可以配置pod应该如何分配内存和CPU资源,以防止资源耗尽并提升云成本。

如果节点没有足够的资源,pod可能会通过抢占或节点压力被驱逐,当进程耗尽内存(OOM)时,因为没有可用的资源,则会被操作系统强制kill掉,如果CPU消耗高于实际限制,则将开始对进程进行限制。

那么,本文来讲解一下如何监控Kubernetes Pods对OOM和CPU限制

Kubernetes OOM

Pod中的每个Container都需要内存才能运行,Kubernetes的限制是在Pod定义或Deployment定义中为每个容器设置的,

在当下所有UNIX系统中都有一种机制为了防止内存超出,来强制终止进程的运行,这种机制下会将该进程标记为 错误137 或者 OOMKilled 。

比如:

yaml 复制代码
State:          Running
      Started:      Thu, 10 Oct 2019 11:14:13 +0200
    Last State:     Terminated
      Reason:       OOMKilled
      Exit Code:    137
      Started:      Thu, 10 Oct 2019 11:04:03 +0200
      Finished:     Thu, 10 Oct 2019 11:14:11 +0200

Exit Code 137表示进程使用的内存超过了允许的数量,必须终止该进程

这是Linux中的一个特性,内核为系统中运行的进程设置一个oom_score值。此外,它允许设置一个名为oom_score_adj的值,Kubernetes使用该值来保障服务质量。它还具有一个OOM Killer,它将审查进程并终止那些使用过多内存的进程。

注意,在Kubernetes中,进程可以达到以下任何一个限制:

  • 在容器上设置的Kubernetes限制
  • 在命名空间上设置的Kubernetes ResourceQuota
  • 这个节点的实际内存大小

内存超卖

限制可以比请求的实际更高,因此所有限制的总和可以超过节点容量,这被称为超卖,这是虚拟化技术中比较常见的一种实现,但是实际上,如果所有容器使用的内存都比请求的内存多,它可能会耗尽节点中的内存。这通常会导致某些 Pod 死亡以释放一些内存

监控Kubernetes OOM

在Prometheus中使用节点导出器时,有一个名为node_vmstat_oom_kill的指标。跟踪OOM kill发生的时候很重要,但你可能想提前知道这样的事件发生之前的情况。

相反,你可以检查一个进程离Kubernetes限制有多近:

在Prometheus中使用node-expoter时,有一个metric为node_vmstat_oom_kill,在追查OOM被kill时的时候,这个指标很重要,但如果我们希望在事件发生之前就能看到它,可以通过检查进程离Kubernetes Limit的差距多大:

vbnet 复制代码
(sum by (namespace,pod,container)
(rate(container_cpu_usage_seconds_total{container!=""}[5m])) / sum by 
(namespace,pod,container)
(kube_pod_container_resource_limits{resource="cpu"})) > 0.8

Kubernetes CPU限制

CPU Throttling是一种当进程即将达到某些资源限制时减慢进程的行为,与内存的情况类似,这些限制可能是:

  • 在容器上设置的Kubernetes Limit。
  • 在命名空间上设置的Kubernetes ResourceQuota。
  • 节点的实际内存大小。

想想下面的类比。我们有一条交通拥堵的高速公路:

  • CPU就是路。
  • 车辆代表了这个过程,其中每辆车都有不同的尺寸。
  • 多通道代表有多个核心。
  • 请求将是一条专用道路,比如自行车道。

CPU限流在这里被表示为交通堵塞: 所有进程都会运行,但是运行的过程会变的缓慢。

Kubernetes中的CPU进程

CPU在Kubernetes中通过共享来处理。每个CPU核心被划分为1024个共享,然后使用Linux内核的cgroups(控制组)特性在运行的所有进程之间进行分配。

如果 CPU 能够处理所有当前的进程,则不需要任何操作。如果进程使用的CPU超过100%,那么就会使用共享。与所有Linux内核一样,Kubernetes使用CFS(完全公平调度器)机制,因此拥有更多共享的进程将获得更多CPU时间。

与内存不同,Kubernetes不会因为CPU限流而杀死pod

可以通过如下命令来检查CPU状态: /sys/fs/cgroup/cpu/cpu.stat

**

CPU 超卖

正如我们在限制和请求文章中看到的,当我们想要限制进程的资源消耗时,设置限制或请求是很重要的。不过,要注意设置的总请求不要大于实际的CPU大小,因为这意味着每个容器都应该有一定数量的CPU。

监控Kubernetes CPU限流

你可以检查一个进程离Kubernetes的限制有多近:

vbnet 复制代码
(sum by (namespace,pod,container)(rate(container_cpu_usage_seconds_total
{container!=""}[5m])) / sum by (namespace,pod,container)
(kube_pod_container_resource_limits{resource="cpu"})) > 0.8

如果我们想要跟踪集群中发生的节流量,cadvisor提供了container_cpu_cfs_throttled_periods_total和container_cpu_cfs_periods_total。有了这两个,您就可以很容易地计算出所有CPU周期内的节流百分比。

最佳实践

  • 小心Limits和requests

Limits 是对节点中的资源设置最大上限的一种方法,但是需要小心配置Limits,因为最终可能导致进程受限或终止。

  • 为驱逐做好准备

通过设置非常低的请求,您可能会认为这将为您的进程授予最小的CPU或内存。但是kubelet将首先驱逐那些使用率高于请求优先的pod,所以你将它们标记为第一个被杀死的!

如果您需要保护特定的Pod免受抢占(当kube-scheduler需要分配一个新的Pod时),请为最重要的进程分配优先级类。

  • CPU限流是一个无声的敌人

通过设置不切实际的限制或过度提交,您可能没有意识到您的进程正在受到限制,并且性能受到影响。主动监视CPU使用情况,并了解容器和名称空间中的实际限制

相关推荐
柏油5 小时前
MySQL InnoDB 行锁
数据库·后端·mysql
咖啡调调。5 小时前
使用Django框架表单
后端·python·django
白泽talk5 小时前
2个小时1w字| React & Golang 全栈微服务实战
前端·后端·微服务
摆烂工程师5 小时前
全网最详细的5分钟快速申请一个国际 “edu教育邮箱” 的保姆级教程!
前端·后端·程序员
一只叫煤球的猫5 小时前
你真的会用 return 吗?—— 11个值得借鉴的 return 写法
java·后端·代码规范
Asthenia04125 小时前
HTTP调用超时与重试问题分析
后端
颇有几分姿色6 小时前
Spring Boot 读取配置文件的几种方式
java·spring boot·后端
AntBlack6 小时前
别说了别说了 ,Trae 已经在不停优化迭代了
前端·人工智能·后端
@淡 定6 小时前
Spring Boot 的配置加载顺序
java·spring boot·后端