06|容器CPU(2):如何正确地拿到容器CPU的开销?

2024-06-08 20:18
文章标签 cpu 正确 容器 06 开销 拿到

本文主要是介绍06|容器CPU(2):如何正确地拿到容器CPU的开销?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

无论是容器的所有者还是容器平台的管理者,我们想要精准的对运行着众多容器的云平台做监控,快速排查例如应用的处理能力下降,节点负载过高等问题,就绕不开容器CPU开销。CPU开销的异常,往往是程序异常最明显的一个指标

一、问题重现

容器中运行top,"%Cpu(s)"那一行中显示的数值,并不是这个容器的 CPU 整体使用率,而是容器宿主机的 CPU 使用率

1.1、进程 CPU 使用率

Linux中每个进程的 CPU 使用率,我们都可以用top命令查看。
比如,每个进程在top命令输出中都有对应的一行,100%就表示这个进程在这个瞬时使用了1个CPU,200%就是使用了2个CPU

在top源代码中看到对于每个进程,top 都会从 proc 文件系统中每个进程对应的 stat 文件中读取 2 个数值。

查看 /proc/[pid]/stat文件中有50多项信息,包括:进程的运行状态父进程PID进程优先级,进程使用的内存等等

这里关注 stat文件中的 14项 utime,15项 stime
在这里插入图片描述

  • utime:表示进程的用户态部分在Linux调度中获得CPU的ticks
  • stime:表示进程的内核态部分在Linux调度中获得CPU的ticks

ticks是什么:

  • 就是Linux操作系统中的一个时间单位,可以理解成秒和毫秒的概念。
  • Linux中有个自己的时钟,会周期性的产生中断,每次中断都会触发Linux内核去做一次进程调度,而这一次中断就是一次tick
  • 因为是周期性的中断,比如1秒钟100次中断,那么一个tick作为一个时间单位看的话,也就是1/100 秒。

举个例子:
假如进程的utime 是130 ticks,就相当于 130*1/100=1.3秒,也就是进程从启动开始,在用户态总共运行了1.3秒。

utime 和 stime 都是一个累计值。

如何计算某个时间段内的进程的总 CPU 运行时间?
(1)分 CPU ticks:

假设 T1和 T2时刻之间是1秒,我们可以获取到 T1 时刻的 utime_1和stime_1,同时获得T2 时刻的 utime_2 和 stime_2 在这1秒的瞬时

  • 进程在用户态获得的 CPU ticks 就是(utime_2 — utime_1
  • 进程在内核态获得的 CPU ticks 就是 stime_2 — stime_1)。

(2)总 CPU ticks:

进程CPU 总的开销就是用户态加上内核态,这1秒瞬时进程总的 CPU ticks 等于 (utime_2 – utime_1) + (stime_2 – stime_1)

ticks如何转化为百分比呢?
根据top的源码,有个公式:

进程的 CPU 使用率 = ((utime_2 – utime_1) + (stime_2 – stime_1)) * 100.0 / (HZ * et * 1 )

  • ((utime_2 – utime_1) + (stime_2 – stime_1)) 是瞬时进程总的 CPU ticks 乘以 100.0 的目的是产生百分比数值
  • HZ :就是tick的频率,1秒钟里ticks的次数,这里的值是100
  • et是上面说的瞬时的时间,也就是utime_1 和 utime_2 这两个值的时间间隔。
  • 1:表示1个CPU

(HZ * et * 1 ) :在这瞬时的时间(et)里,1个CPU所包含的ticks数目。
进程的CPU使用率 =(进程的ticks/单个CPU总ticks)*100


1.2、系统CPU使用率

/proc/stat 就是整个系统的CPU使用率,是自系统启动以来的累计值,文件中 CPU 这行有10列数据,前8列数据正好对应top输出中"%Cpu(s)"那一行里的 8 项数据,也就是在上一讲中,我们介绍过的 user/system/nice/idle/iowait/irq/softirq/steal 这 8 项。

下面的图:
前8列的数值,分别是不同CPU类型的ticks的累计值,因此相减就是对应时间段的ticks。
在这里插入图片描述

在这里插入图片描述

计算每一种CPU使用率的百分比:
将时间段内(例如1秒钟)的ticks相加得到一个总值,然后拿某一项的ticks值除以这个总值,比如说计算idle CPU的使用率就是:

单项CPU使用率 = 【单项(如id项) / us + sy + ni + id + wa + hi + si + st 】* 100%

1203 / 0 + 0 + 0 + 1203 + 0 + 0 + 0 + 0=100%

对于单个进程的 CPU 使用率计算,我们需要读取对应进程的 /proc/[pid]/stat 文件,将进程瞬时用户态和内核态的 ticks 数相加,就能得到进程的总 ticks

然后我们运用公式“(进程的 ticks / 单个 CPU 总 ticks) * 100.0”计算出进程 CPU 使用率的百分比值。

对于系统的 CPU 使用率,需要读取 /proc/stat 文件,得到瞬时各项 CPU 使用率的 ticks 值,相加得到一个总值,单项值除以总值就是各项 CPU 的使用率。


二、解决问题(计算容器CPU使用率)

容器中使用top命令,它只能显示整个节点中各项CPU的使用率,不能显示单个容器的各项CPU的使用率

CPU Cgroup控制组里有个文件中可读项:cpuacct.stat 包含了两个统计值,这个控制组里所有进程的内核态 ticks用户态 ticks

然后利用上面的公式去计算CPU的利用率。

CPU使用率=((utime2-utime1)+(stime2-stime1)) * 100 / (HZ * et * 1)

整个容器的 CPU 使用率的百分比就是 ( (174021 - 173820) + (4 – 4)) * 100.0 / (100 * 1 * 1) = 201, 也就是 201%
重点命令:
在这里插入图片描述
从每个容器的 CPU Cgroup 控制组里的 cpuacct.stat 的统计值中,可以比较快地得到整个容器的 CPU 使用率。


三、重点总结

  1. Linux里获取CPU 使用率的工具,比如top,都是通过读取proc文件系统下的 stat 文件来得到CPU 使用了多少 ticks。 $ cat /proc/stat
  2. ticks 是Linux中的一个时间单位,可以理解成类似毫秒的概念。
  3. 对于每个进程来说,它的stat文件是 /proc/[pid]/stat ,里面包含了进程用户态内核态的 ticks数目;
  4. 对于整个节点,它的stat文件是 /proc/stat 里面包含了 user / system / nice / idle / iowait 等不同类型CPU开销的类型的 ticks。
  5. 由于 /proc/stat 是整个节点的全局的状态文件,不属于任何一个namespace,因此无法通过读取这个文件来获取单个容器的CPU 使用率。
  6. 获取单个容器的CPU 使用率:
    可以从CPU Cgroup 控制组里的每个统计文件 cpuacct.stat 中获取。
    单个容器 CPU 使用率 =((utime_2 – utime_1) + (stime_2 – stime_1)) * 100.0 / (HZ * et * 1 )


四、评论

问题1:
ticks 1s中是100次,这个怎么查呢?

回答1:USER_HZ, 可以用命令 "getconf CLK_TCK"拿

问题2:
容器的cpu使用就必须要在容器内进行,从宿主机是无法计算的,是这样吗?

回答2:不是这样的,从宿主机也可以得到容器对应的CPU Cgroup里的值。

问题3:
容器运行时比如docker,在做容器化的时候,有没有办法构造出一个和物理机一样的proc文件系统呢?这样的话,容器环境和虚拟机也没啥差别了,物理机上的应用也可以无障碍运行在容器环境中。

回答3:https://github.com/lxc/lxcfs, lxcfs可以为每个容器虚拟一些/proc下的文件,比如/proc/stat

问题4:
像Prometheus或者k8s自己的metrics server获取到的pod各个资源使用率(cpu men net io)也是这样通过查看进程/proc来计算得出的吗?如果是这样的话,指标数据太多,运算太大会不会也会消耗节点资源呢

回答4:cAdvisor就是通过读取sys cgroup 或者 /proc下的状态信息来得到container cpu/mem/net/io metrics的。
一般一个节点上的container数量是小于1000的,metrics获取的周期在10s 的情况下, 这个资源消耗不会很大。

问题5:
在k8s集群中,使用metrics查看到整个pod的资源用量,这个粒度已经够了吧?我的理解是如果pod内不是单一容器,或者容器内有多个进程,这个时候才应该考虑进程级的cpu用量。

回答5:是的

问题6:
问题1)生产上面 如果把nginx放入到pod中,是不是会碰到目前为止老师说的那些所有问题 比如关闭容器sigterm主进程nginx master。所有的nginx worker都被sigkill。
问题2)然后容器里面的各个进程用的cpu总合是会被k8s metrics计算到的吧。

回答6
. > 问题1
nginx 似乎有自己的master process 和 client processes之间的socket连接。如果nginx master作为容器里的pid 1, 当关闭容器的时候master收到SIGTERM, 而其他的client子进程是看到socket连接断开之后,主动退出的。
.> 问题2
是的, 用cAdvisor可以统计整个容器的cpu.



五、附加问题

lxcfs 怎么使用的

lxcfs 是通过文件挂载的方式,把 cgroup 中关于系统的相关信息读取出来,通过 docker 的 volume 挂载给容器内部的 proc 系统。 然后让 docker 内的应用读取 proc 中信息的时候以为就是读取的宿主机的真实的 proc。

在这里插入图片描述

解释一下这张图,当我们把宿主机的/var/lib/lxcfs/proc/memoinfo文件挂载到 Docker 容器的/proc/meminfo位置后,容器中进程读取相应文件内容时,lxcfs 的 /dev/fuse 实现会从容器对应的 Cgroup 中读取正确的内存限制。从而使得应用获得正确的资源约束。 cpu 的限制原理也是一样的。

lxcfs 分别在docker和k8s 情况的使用说明,参考阅读文档:
https://juejin.cn/post/6847902216511356936

这篇关于06|容器CPU(2):如何正确地拿到容器CPU的开销?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1043205

相关文章

使用Python检查CPU型号并弹出警告信息

《使用Python检查CPU型号并弹出警告信息》本教程将指导你如何编写一个Python程序,该程序能够在启动时检查计算机的CPU型号,如果检测到CPU型号包含“I3”,则会弹出一个警告窗口,感兴趣的小... 目录教程目标方法一所需库步骤一:安装所需库步骤二:编写python程序步骤三:运行程序注意事项方法二

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

【测试】输入正确用户名和密码,点击登录没有响应的可能性原因

目录 一、前端问题 1. 界面交互问题 2. 输入数据校验问题 二、网络问题 1. 网络连接中断 2. 代理设置问题 三、后端问题 1. 服务器故障 2. 数据库问题 3. 权限问题: 四、其他问题 1. 缓存问题 2. 第三方服务问题 3. 配置问题 一、前端问题 1. 界面交互问题 登录按钮的点击事件未正确绑定,导致点击后无法触发登录操作。 页面可能存在

K8S(Kubernetes)开源的容器编排平台安装步骤详解

K8S(Kubernetes)是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。以下是K8S容器编排平台的安装步骤、使用方式及特点的概述: 安装步骤: 安装Docker:K8S需要基于Docker来运行容器化应用程序。首先要在所有节点上安装Docker引擎。 安装Kubernetes Master:在集群中选择一台主机作为Master节点,安装K8S的控制平面组件,如AP

Spring框架5 - 容器的扩展功能 (ApplicationContext)

private static ApplicationContext applicationContext;static {applicationContext = new ClassPathXmlApplicationContext("bean.xml");} BeanFactory的功能扩展类ApplicationContext进行深度的分析。ApplicationConext与 BeanF

容器编排平台Kubernetes简介

目录 什么是K8s 为什么需要K8s 什么是容器(Contianer) K8s能做什么? K8s的架构原理  控制平面(Control plane)         kube-apiserver         etcd         kube-scheduler         kube-controller-manager         cloud-controlle

前端-06-eslint9大变样后,如何生成旧版本的.eslintrc.cjs配置文件

目录 问题解决办法 问题 最近在写一个vue3+ts的项目,看了尚硅谷的视频,到了配置eslintrc.cjs的时候我犯了难,因为eslint从9.0之后重大更新,跟以前完全不一样,但是我还是想用和老师一样的eslintrc.cjs文件,该怎么做呢? 视频链接:尚硅谷Vue项目实战硅谷甄选,vue3项目+TypeScript前端项目一套通关 解决办法 首先 eslint 要

Java程序到CPU上执行 的步骤

相信很多的小伙伴在最初学习编程的时候会容易产生一个疑惑❓,那就是编写的Java代码究竟是怎么一步一步到CPU上去执行的呢?CPU又是如何执行的呢?今天跟随小编的脚步去化解开这个疑惑❓。 在学习这个过程之前,我们需要先讲解一些与本内容相关的知识点 指令 指令是指导CPU运行的命令,主要由操作码+被操作数组成。 其中操作码用来表示要做什么动作,被操作数是本条指令要操作的数据,可能是内存地址,也

C++ STL关联容器Set与集合论入门

1. 简介 Set(集合)属于关联式容器,也是STL中最实用的容器,关联式容器依据特定的排序准则,自动为其元素排序。Set集合的底层使用一颗红黑树,其属于一种非线性的数据结构,每一次插入数据都会自动进行排序,注意,不是需要排序时再排序,而是每一次插入数据的时候其都会自动进行排序。因此,Set中的元素总是顺序的。 Set的性质有:数据自动进行排序且数据唯一,是一种集合元素,允许进行数学上的集合相

Spring容器上下文

目录 一 什么是spring容器上下文 二 spring容器上下文可以做什么 三 如何使用 1.实现ApplicationContextAware接口 2.代码测试 一 什么是spring容器上下文 你可以把它理解成就是spring容器,它主要用于管理Bean对象,包括bean的生命周期,bean的注入等等。 二 spring容器上下文可以做什么 我们刚刚上面