一、服务器CPU简介

CPU的概念:

CPU(Central Processing Unit)又叫中央处理器,其主要功能是进行运算和逻辑运算,内部结构大概可以分为控制单元、算术逻辑单元和存储单元等几个部分。按照其处理信息的字长可以分为:八位微处理器、十六位微处理器、三十二位微处理器以及六十四位微处理器等等。 

  目前,服务器的CPU仍按CPU的指令系统来区分,通常分为CISC型CPU和RISC型CPU两类,后来又出现了一种64位的VLIM(Very Long Instruction Word超长指令集架构)指令系统的CPU。

  • CPU架构:
    • 复杂指令集CPU:X86架构:如intel、AMD
    • 精简指令集CPU:ARM架构如飞腾、PowerPC架构如IBM
  • CPU主频:
    • CPU内核的时钟频率,它是指CPU内部晶振的频率,表示在CPU内数字脉冲信号震荡的速度,常用单位为MHz,它反映了CPU的基本工作节拍,很大程度上影响了CPU的运算速度,CPU的很多性能指标,都会和时钟频率有关,所以一般来说,主频频率越高,CPU每秒处理的数据就越多。
  • CPU核心线程:
    • 我们任务管理器下看到的CPU总数,是你的CPU物理核心数用超线程技术虚拟出来的核心数
    • 线程数就是模拟出来的CPU核心数(注意不是CPU物理核心数)
    • 对于一个CPU,线程数总是大于或等于核心数(物理核心)的。一个核心(物理核心)最少对应一个线程,但通过超线程技术,一个核心可以对应两个线程,也就是说它可以同时运行两个线程。这也就解释了为什么会有六核心(物理核心)十二线程(CPU核心数)的原因。
  • CPU缓存:
    • 用于减少处理器访问内存所需平均时间的部件。在金字塔式存储体系中它位于自顶向下的第二层,仅次于CPU寄存器。其容量远小于内存,但速度却可以接近处理器的频率。

  • Architecture: #x86架构/arm架构
  • Thread(s) per core: #每个核心的线程数量
  • Core(s) per socket: #每颗物理CPU的核数
  • CPU socket(s): #物理CPU个数
  • CPU MHz: #cpu主频,也就是CPU内核的时钟频率,运算速度

cpu核数计算

CPU总核数=物理CPU个数 * 每颗物理CPU的核数 =8*1=8

总逻辑CPU数=物理CPU个数 * 每颗物理CPU的核数 * 超线程数* 复用比=8*1*1=8

二、CPU性能指标分类

cpu的性能指标有如下图几种:

三、CPU使用率详解

  • 频率:
单位时间内完成振动或振荡的次数或周数
常用单位是赫兹。1赫兹等于1次/秒或1周/秒 

频率单位有:
Hz(赫)、kHz(千赫)、MHz(兆赫)、GHz(吉赫)。
其中1GHz=1000MHz,1MHz=1000kHz,1kHz=1000Hz

[root@localhost hello]# cat /proc/cpuinfo  //虚拟机 pc台式机的频率
processor       : 0
vendor_id       : GenuineIntel
cpu family      : 6
model           : 94
model name      : Intel(R) Core(TM) i7-6700 CPU @ 3.40GHz
  • LINUX系统时钟频率:
LINUX系统时钟频率是一个常数HZ来决定的,如:通常f=3.40GHz,那么他的精度度就是0.29ns(纳秒)。 
1GHz周期是1ns。
也就是说每0.29ns一次中断。所以一般来说Linux的精确度是1ns之内。
  • 时钟周期:
时钟周期也称为振荡周期,定义为时钟频率的倒数。
时钟周期是计算机中最基本的、最小的时间单位。
在一个时钟周期内,CPU仅完成一个最基本的动作。时钟周期是一个时间的量。
1GHz周期是1ns。
周期单位:
s(秒)、ms(毫秒)、μs(微秒)、ns(纳秒),
其中:1s=1000ms,1 ms=1000μs,1μs=1000ns。
  • 指令周期:
指令周期(Instruction Cycle):取出并执行一条指令的时间。
计算机执行指令的过程可以分为以下三个步骤:
1.Fetch(取指)也就是从 PC 寄存器里找到对应的指令地址
2.Decode(译码)根据指令寄存器里面的指令,解析成要进行什么样的操作
3.Execute(执行指令)进行算术逻辑操作、数据传输或者直接的地址跳转

对于一个指令周期来说,我们取出一条指令,然后执行它,至少需要两个 CPU 周期。
取出指令至少需要一个 CPU 周期,执行至少也需要一个 CPU 周期,复杂的指令则需要更多的 CPU 周期。
而一个CPU周期是若干时钟周期之和。

  • CPU时间(monotonic time-mapping - 单调时间变换):
    • 从操作系统开启算起,CPU就开始工作了,CPU记录自己在工作中总共使用的“时间”的累计值,并把它保存在系统中
    • 这些时间由变量jiffies来记录。系统每次启动时jiffies初始化为0,每来一个timer interrupt(时钟中断),jiffies加1,也就是说它代表系统启动后流逝的tick数
    • jiffies一定是单调递增的
    • jiffies是内核中的一个全局变量,用来记录自系统启动一来产生的时钟中断次数,在linux中,一个中断大致可理解为操作系统进程调度的最小时间片,不同linux内核可能值有不同,通常在1ms到10ms之间
    • 全局变量jiffies用来记录自系统启动以来产生的节拍的总数。启动时,内核将该变量初始化为0,此后,每次时钟中断处理程序都会增加该变量的值。一秒内时钟中断的次数等于Hz,所以jiffies一秒内增加的值也就是Hz。 系统运行时间以秒为单位,等于jiffies/Hz。
  • CPU状态类型:
    • cpu time => cpu user time/sys time/nice time/idle time/irq.....

(默认情况下,top命令以3秒的频率更新输出结果)

参数

解析(单位:jiffies 记录系统启动以来产生的节拍数,一个节拍可看为进程调度的最小时间片,jiffies一定是单调递增的)

user(1204317)

从系统启动开始累计到当前时刻,处于用户态的运行时间,不包含nice值为负的进程。用户CPU使用率包括用户态 CPU 使用率(user)和低优先级用户态 CPU 使用率(nice),表示 CPU 在用户态运行的时间百分比。用户 CPU 使用率高,通常说明有应用程序比较繁忙。

nice(189103)

从系统启动开始累计到当前时刻,nice值为负的进程所占用的CPU时间

system(1171340)

从系统启动开始累计到当前时刻,处于核心态的运行时间。系统CPU使用率表示 CPU 在内核态运行的时间百分比(不包括中断)。系统 CPU 使用率高,说明内核比较繁忙。

idle(60581145)

从系统启动开始累计到当前时刻,除IO等待时间以外的其它等待时间

iowait(90421)

从系统启动开始累计到当前时刻,IO等待时间。等待 I/O 的 CPU 使用率,通常也称为 iowait,表示等待 I/O 的时间百分比。iowait 高,通常说明系统与硬件设备的 I/O 交互时间比较长。

irq(132530)

从系统启动开始累计到当前时刻,硬中断时间。表示内核调用硬中断处理程序

softirq(80465)

从系统启动开始累计到当前时刻,软中断时间。表示内核调用软中断处理程序

stealstolen(0)

在虚拟机环境下运行其他操作系统所花费的时间。窃取 CPU 使用率(steal)表示被其他虚拟机占用的 CPU 时间百分比

guest(0)

运行在访客模式下所花费的时间。客户 CPU 使用率(guest)表示运行客户虚拟机的 CPU 时间百分比

guest_nice(0)

运行在访客模式下,nice值为负的进程所占用的CPU时间

nice值解释:

每一个进程都有一个 PRI 和 NI 值,可通过 ps -ef -l 命令或者top命令查看。PRI 还是比较好理解的,即进程的优先级,或者通俗点说就是程序被 CPU 执行的先后顺序,此值越小进程的优先级别越高。那 NI 呢?就是我们所要说的 nice 值了,其表示进程可被执行的优先级的修正数值。如前面所说,PRI值越小越快被执行,那么加入 nice 值后,将会使得 PRI 变为:PRI(new)=PRI(old)+nice。这样,当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行

  • 获取CPU各状态当前时间下的累计值:

在/proc伪文件系统中会记录对应的时间累计值,这些总的累计值会存在/proc/stat文件中。

cat /proc/stat 可以观察这些数值

各进程的累计值各自存放在各自的目录文件下,/proc/进程号/stat

在讲CPU使用率之前,我们来看看下面这个例子:
一台服务器
12:00开机后一直到12:30截止
cpu被使用在用户态 的时间一共是 8分钟
cpu被使用在内核态 的时间一共是 1.5分钟
cpu被使用在IO等待状态 的时间一共是 0.5分钟
cpu被使用在idle(空闲状态) 的时间一共是 20分钟
cpu被使用在其他几个状态的时间是 0分钟

(user(8mins) + sys(1.5mins) + iowait(0.5mins) + 0 + 0 + 0 + 0) / (30mins)
= 1 - ((idle(20mins) / (30mins))
= 30%

cpu的使用率  = (所有非空闲状态的cpu时间总和) / (所有状态cpu时间的总和)
           	=  1 - ((空闲状态cpu时间总和) / (所有状态cpu时间的总和))
(问题:按照上面的方法计算,只能算出cpu在30分钟内的总平均时间,精度太低没参考价值)

上面是从开机开始算的,由于前面我们提到过,jiffies 记录的是系统启动以来产生的节拍数,且jiffies单调递增,那上面cpu使用率的计算公式就要发生变化了,cpu使用率表示的是一定时间下CPU时间增量的变化率:

    • 采样两个足够短的时间间隔的 cpu 快照,分别为 t1,t2,其中 t1、t2 均包含(user、nice、system、idle、iowait、irq、softirq、stealstolen、 guest)9个元素;
    • 计算总的 cpu 时间:
      • 把第一次的所有 cpu 使用情况求和,得到 total_t1;
      • 把第二次的所有 cpu 使用情况求和,得到 total_t2;
      • 这个时间间隔内的所有时间片,即 totalCpuTime = total_t2 - total_t1 ;
      • idle 对应第四列的数据,用第二次的 idle - 第一次的 idle 即可
      • idle = idle_t2 – idle_t1
      • cpuUsage = 100 * (1-(idle_t2 – idle_t1) / (total_t2 – total_t1))

  • cpu时间累计递增观察
    • 我们取30min区间观察CPU0号核cpu idle状态时间数值,通过指标获取,我们可以看到,整体数值是单调递增的
    • node_cpu_seconds_total{ instance="192.168.1.190:9100", job="node_exporter", nodename="V6-node-exporter"}
    • 观察0号CPU核的user状态时间数值,也是递增的

  • 使用promethues获取各种指标,计算CPU使用率
    • 获取CPU时间:
      • 获取各核cpu总时间累计:
        • node_cpu_seconds_total{ instance="192.168.1.190:9100", job="node_exporter", nodename="V6-node-exporter"}
      • 获取各核cpu1分钟的时间增量:
        • increase(node_cpu_seconds_total{ instance="192.168.1.190:9100", job="node_exporter", nodename="V6-node-exporter"}[1m])
      • 获取各核cpu时间在1分钟内的增量总和:
        • sum(increase(node_cpu_seconds_total{ instance="192.168.1.190:9100", job="node_exporter", nodename="V6-node-exporter"}[1m]))
    • 获取cpu空闲状态时间:
      • 获取各核cpu空闲状态idle时间累计:
        • node_cpu_seconds_total{ mode="idle",instance="192.168.1.190:9100", job="node_exporter", nodename="V6-node-exporter"}
      • 获取各核cpu空闲状态时间 在1分钟的增量:
        • increase(node_cpu_seconds_total{ mode="idle",instance="192.168.1.190:9100", job="node_exporter", nodename="V6-node-exporter"}[1m])
      • 获取cpu各核空闲状态时间在1分钟内的增量总和:
        • sum(increase(node_cpu_seconds_total{ mode="idle",instance="192.168.1.190:9100", job="node_exporter", nodename="V6-node-exporter"}[1m])
    • 计算系统PU使用率(1分钟增量变化情况)
        • cpuUsage = 100 * (1-(idle_t2 – idle_t1) / (total_t2 – total_t1))
      • 将变量套进公式:
        • 100 * (1 - ((sum(increase(node_cpu_seconds_total{ mode="idle",instance="192.168.1.190:9100", job="node_exporter", nodename="V6-node-exporter"}[1m]))) / (sum(increase(node_cpu_seconds_total{ instance="192.168.1.190:9100", job="node_exporter", nodename="V6-node-exporter"}[1m])))))

四、CPU平均活跃进程数详解(平均负载)(Load Average

  • 平均负载概念:
    • 平均负载又可以理解成:单位时间的“平均活跃进程数”。这里的活跃进程,主要指可运行状态的进程不可中断状态的进程。它和CPU使用率没有直接的关系。
  • 可运行状态和不可中断状态进程:
    • 可运行状态进程
      • 可运行状态的进程是指正在使用CPU或者等待CPU的进程,也就是我们通过ps命令能查看到的Running或者Runnable状态的进程。
    • 不可中断状态进程
      • 不可中断进程是指正处于内核关键的进程,这些是不能打断的。也就是我们通过ps命令能查看到的D状态的进程比如,为了保证磁盘数据一致性,回写磁盘的进程就不能打断。不可中断状态是系统对硬件设备的一种保护机制。

。。。。。。。。

五、CPU上下文切换

六、CPU缓存命中率

七、CPU运行队列

。。。。。。。。未完待续。。。。。。。。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐