CPU使用率是单位时间内CPU使用情况的统计,以百分比方式展示。

$ top
top - 11:46:45 up 7 days, 11:52, 1 user, load average: 0.00, 0.01, 0.00
Tasks: 198 total, 1 running, 197 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.2 us, 0.2 sy, 0.0 ni, 99.7 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 4044232 total, 420136 free, 1061244 used, 2562852 buff/cache
KiB Swap: 1046524 total, 1043128 free, 3396 used. 2619124 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
921 root 20 0 531332 138408 58972 S 0.7 3.4 41:31.24 Xorg

  参数解析如下:

  • %user(us),代表用户态 CPU 时间。不包括下面的 nice 时间,但包括了 guest 时间。
  • %nice(ni),代表低优先级用户态 CPU 时间,也就是进程的 nice 值被调整为 1-19 之间时的 CPU 时间。nice 可取值范围是 -20 到 19,数值越大,优先级反而越低。
  • %system(sys),代表内核态 CPU 时间。
  • %idle(id),代表空闲时间。不包括等待 I/O 的时间(iowait)。
  • %iowait(wa),代表等待 I/O 的 CPU 时间,处于不可中断状态。
  • %irq(hi),代表处理硬中断的 CPU 时间。
  • %softirq(si),代表处理软中断的 CPU 时间。
  • %steal(st),代表当系统运行在虚拟机中的时候,被其他虚拟机占用的 CPU 时间。
  • %guest(guest),代表通过虚拟化运行其他操作系统的时间,也就是运行虚拟机的 CPU 时间。
  • %guest_nice(gnice),代表以低优先级运行虚拟机的时间。
  • %CPU,每个进程的实时 CPU 使用率,是用户态和内核态 CPU 使用率的总和。包括进程用户空间使用的 CPU、通过系统调用执行的的内核空间 CPU 、以及在就绪队列等待运行的 CPU。在虚拟化环境中,它还包括了运行虚拟机占用的 CPU。

      

查看CPU使用的命令

  (1)top 默认使用 3 秒时间间隔,显示了系统总体的 CPU 和内存使用情况,以及各个进程的资源总体使用情况。vmstat、mpstat 提高更详细的分析多进程或者多线程应用。

  (2)ps 使用的却是进程的整个生命周期,显示了每个进程的资源使用情况。

  (3)pidstat 查看每个进程的详细CPU使用情况,包括用户态和内核态CPU。

  

CPU使用率是通过CPU时间计数计算而来

  而我们通常所说的 CPU 使用率,就是除了空闲时间外的其他时间占总 CPU 时间的百分比:

    

  事实上,性能工具是取间隔时间作差,得到这段时间的平均CPU使用率:

    

  同样Linux也给每个进程统计信息,/proc/[pid]/stat,通过上述方式计算使用率。

  为了维护 CPU 时间,Linux 通过事先定义的节拍率HZ,触发时间中断,并使用全局变量 Jiffies 记录了开机以来的节拍数。每发生一次时间中断,Jiffies 的值就加 1。节拍率 HZ 是内核的可配选项,可以设置为 100、250、、1000 等。不同的系统可能设置不同数值,你可以通过查询 /boot/config 内核选项来查看它的配置值。$ grep 'CONFIG_HZ=' /boot/conf-$(uname -r)

  节拍率 HZ 是内核选项,用户空间程序并不能直接访问,为了方便用户空间程序,内核还提供了一个用户空间节拍率 USE_HZ,它总是固定为 100,也就是 1/100 秒。

  Linux 通过 /proc 虚拟文件系统,向用户空间提供系统内部状态的信息,而 /proc/stat 提供的就是系统的 CPU 和任务统计信息,每一列则表示不同场景下 CPU 的累加节拍数,单位是 USER_HZ。

  

CPU使用率过高,如何进一步分析进程

  perf 以性能事件采样为基础,不仅可以分析系统的各种事件和内核性能,还可以用来分析指定应用程序的性能问题。

  (1)perf top,类似于 top,它能够实时显示占用 CPU.时钟最多的函数或者指令,中间不保存数据,因此可以用来查找热点函数。若定位到的函数是十六进制地址,说明没有找到待分析进程所依赖的库,解决方法是添加依赖库,或用perf record后在有依赖的环境中查看。

$ perf top
Samples: 175 of event 'cpu-clock', Event count (approx.): 43750000
Overhead Shared Object Symbol
6.86% perf [.] 0x00000000000a34ac
5.71% [kernel] [k] kallsyms_expand_symbol.constprop.1
5.14% [kernel] [k] format_decode // 第一行 采样数(Samples)、事件类型(event)和事件总数量(Event count)
// 采集了 175 个 cpu-clock 事件,而总事件数则为 43750000
// 采样数过少,只有十几个时,下面的排序和百分比没有实际参考价值
// Overhead 是该符号的性能事件在所有采样中的比例
// Shared 是该函数或指令所在的动态共享对象(Dynamic Shared Object),如内核、进程名、动态链接库名、内核模块名等。
// Object 是动态共享对象的类型。比如 [.] 表示用户空间的可执行程序、或者动态链接库,而 [k] 则表示内核空间。
// Symbol 是符号名,也就是函数名。当函数名未知时,用十六进制的地址来表示。

  (2)perf record 和 perf report,perf record 提供了保存数据的功能,保存后的数据,需要用 perf report 解析展示,用于离线或者后续的分析。

$ sudo perf record -g --all-cpus
// ^C 停止记录,数据保存在 perf.data 中,-g 开启调用关系的采样,--all-cpus 采集所有CPU事件
$ sudo perf report -g

  

CPU使用率过高的总体分析步骤

  Step1:通过 top、pidstat 找到哪个进程CPU使用率过高;

  Step2:通过 perf 找到该进程中具体哪个函数使用过高。$ perf top -g -p <pid_id>

  Step3:通过 grep 查看该函数中的具体内容。$ grep -nr "<function_name>" <file_path>

  性能问题:

  (1)用户 CPU 和 Nice CPU 高,说明用户态进程占用了较多的 CPU,所以应该着重排查进程的性能问题。

  (2)系统 CPU 高,说明内核态占用了较多的 CPU,所以应该着重排查内核线程或者系统调用的性能问题。

  (3)I/O 等待 CPU 高,说明等待 I/O 的时间比较长,所以应该着重排查系统存储是不是出现了 I/O 问题。

  (4)软中断和硬中断高,说明软中断或硬中断的处理程序占用了较多的CPU,所以应该着重排查内核中的中断服务程序。

  

系统的 CPU 使用率很高,但为啥却找不到高 CPU 的应用?

  系统的 CPU 使用率,不仅包括进程用户态和内核态的运行,还包括中断处理、等待 I/O 以及内核线程等。所以,当你发现系统的 CPU 使用率很高的时候,不一定能找到相对应的高 CPU 使用率的进程。

  如下系统总CPU使用率80.8%,而单个进程的CPU使用率都较小。需要通过 top 、pidstat 等交叉确认系统和各进程的CPU使用率。

  并且仔细观察进程列表中的状态S,查看R、S等状态的进程是否正常。

$ top
...
%Cpu(s): 80.8 us, 15.1 sy, 0.0 ni, 2.8 id, 0.0 wa, 0.0 hi, 1.3 si, 0.0 st
... PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
6882 root 20 0 8456 5052 3884 S 2.7 0.1 0:04.78 docker-containe
6947 systemd+ 20 0 33104 3716 2340 S 2.7 0.0 0:04.92 nginx
7494 daemon 20 0 336696 15012 7332 S 2.0 0.2 0:03.55 php-fpm

发生以上情况的原因

(1)进程在不停地崩溃重启,比如因为段错误、配置错误等等,这时,进程在退出后可能又被监控系统自动重启了,而启动过程的资源初始化,很可能会占用相当多的 CPU。

(2)这些进程都是短时进程,也就是在其他应用内部通过 exec 调用的外面命令。这些命令一般都只运行很短的时间就会结束,你很难用 top 这种间隔时间比较长的工具发现。

发送上述问题的解决方法是找到父进程,从父进程入手,排查问题:

方法一

(1)通过 top、pidstat 等找到可疑进程;

(2)通过 pstree 用树状形式显示该进程与其他进程的关系;

(3)通过 grep 找到具体调用代码

方法二

(1)通过 perf record -g // 记录性能事件,等待大约 几秒后按 Ctrl+C 退出

(2)通过 perf report

方法三

  execsnoop 就是一个专为短时进程设计的工具,一般用于分析 Linux 内核的运行时行为。它通过 ftrace 实时监控进程的 exec() 行为,并输出短时进程的基本信息,包括进程 PID、父进程 PID、命令行参数以及执行的结果。

  https://github.com/brendangregg/perf-tools/blob/master/execsnoop

  

系统中出现大量不可中断进程和僵尸进程怎么办?

进程状态

  • R 是 Running 或 Runnable 的缩写,表示进程在 CPU 的就绪队列中,正在运行或者正在等待运行。
  • D 是 Disk Sleep 的缩写,也就是不可中断状态睡眠(Uninterruptible Sleep),一般表示进程正在跟硬件交互,并且交互过程不允许被其他进程或中断打断。
  • Z 是 Zombie 的缩写,表示僵尸进程,也就是进程实际上已经结束了,但是父进程还没有回收它的资源(比如进程的描述符、PID 等)。
  • S 是 Interruptible Sleep 的缩写,也就是可中断睡眠状态,表示进程因为等待某个事件而被系统挂起。当进程等待的事件发生时,它会被唤醒并进入 R 状态。
  • I 是 Idle 的缩写,也就是空闲状态,用在不可中断睡眠的内核线程上。硬件交互导致的不可中断进程用 D 表示,但对某些内核线程来说,它们有可能实际上并没有任何负载,用 Idle 正是为了区分这种情况。要注意,D 状态的进程会导致平均负载升高, I 状态的进程却不会。
  • T 或者 t,是 Stopped 或 Traced 的缩写,表示进程处于暂停或者跟踪状态。如(1)向一个进程发送 SIGSTOP 信号,它就会因响应这个信号变成暂停状态(Stopped);再向它发送 SIGCONT 信号,进程又会恢复运行(如果进程是终端里直接启动的,则需要你用 fg 命令,恢复到前台运行)。(2)调试器 gdb 调试一个进程时,在使用断点中断进程后,进程就会变成跟踪状态,这其实也是一种特殊的暂停状态,只不过你可以用调试器来跟踪并按需要控制进程的运行。
  • X 是 Dead 的缩写,表示进程已经消亡,所以你不会在 top 或者 ps 命令中看到它。

  不可中断状态,是为了保证进程数据与硬件状态一致,并且正常情况下,不可中断状态在很短时间内就会结束。所以,短时的不可中断状态进程,我们一般可以忽略。但如果系统或硬件发生了故障,进程可能会在不可中断状态保持很久,甚至导致系统中出现大量不可中断进程。这时系统可能出现了 I/O 等性能问题。

  僵尸进程,这是多进程应用很容易碰到的问题。正常情况下,当一个进程创建了子进程后,它应该通过系统调用 wait() 或者 waitpid() 等待子进程结束,回收子进程的资源;而子进程在结束时,会向它的父进程发送 SIGCHLD 信号,所以,父进程还可以注册 SIGCHLD 信号的处理函数,异步回收资源。如果父进程没这么做,或是子进程执行太快,父进程还没来得及处理子进程状态,子进程就已经提前退出,那这时的子进程就会变成僵尸进程。

  通常,僵尸进程持续的时间都比较短,在父进程回收它的资源后就会消亡;或者在父进程退出后,由 init 进程回收后也会消亡。但是一旦父进程没有处理子进程的终止,还一直保持运行状态,那么子进程就会一直处于僵尸状态。大量的僵尸进程会用尽 PID 进程号,导致新进程不能创建。

$ ps aux | grep /app
root 4009 0.0 0.0 4376 1008 pts/0 Ss+ 05:51 0:00 /app
root 4287 0.6 0.4 37280 33660 pts/0 D+ 05:54 0:00 /app
root 4288 0.6 0.4 37280 33668 pts/0 D+ 05:54 0:00 /app

  s 表示这个进程是一个会话的领导进程,而 + 表示前台进程组。

  进程组表示一组相互关联的进程,比如每个子进程都是父进程所在组的成员。在后台运行的命令,构成后台进程组;在前台运行的命令,构成前台进程组。

  会话是指共享同一个控制终端的一个或多个进程组。

$ top
top - 05:56:23 up 17 days, 16:45, 2 users, load average: 2.00, 1.68, 1.39
Tasks: 247 total, 1 running, 79 sleeping, 0 stopped, 115 zombie
%Cpu0 : 0.0 us, 0.7 sy, 0.0 ni, 38.9 id, 60.5 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu1 : 0.0 us, 0.7 sy, 0.0 ni, 4.7 id, 94.6 wa, 0.0 hi, 0.0 si, 0.0 st
... PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
4340 root 20 0 44676 4048 3432 R 0.3 0.0 0:00.05 top
4345 root 20 0 37280 33624 860 D 0.3 0.0 0:00.01 app
4344 root 20 0 37280 33624 860 D 0.3 0.4 0:00.01 app
1 root 20 0 160072 9416 6752 S 0.0 0.1 0:38.59 systemd // 第一行的平均负载( Load Average),平均负载正在升高,
// 而 1 分钟内的平均负载已经达到系统的 CPU 个数,说明系统很可能已经有了性能瓶颈。
// 第二行,有 1 个正在运行的进程,但僵尸进程比较多,而且还在不停增加,说明有子进程在退出时没被清理。
// 第三、四行,用户 CPU 和系统 CPU 都不高,但 iowait 分别是 60.5% 和 94.6%,好像有点儿不正常。
// 最后,CPU 使用率都不高;但有两个进程处于 D 状态,它们可能在等待 I/O。

  第一点,iowait 太高了,导致系统的平均负载升高,甚至达到了系统 CPU 的个数。

  第二点,僵尸进程在不断增多,说明有程序没能正确清理子进程的资源。

  iowait 分析

  从系统整体了解 I/O 情况 -> 定位到具体进程 -> 定位到具体函数

  (1)dstat 是一个新的性能工具,它吸收了 vmstat、iostat、ifstat 等几种工具的优点,可以同时观察系统的 CPU、磁盘 I/O、网络以及内存使用情况,本例需关注系统整体和 I/O 的问题。

$ dstat 1 10  // 输出间隔 1 秒,总共输出 10 组数据
You did not select any stats, using -cdngy by default.
----total-cpu-usage---- -dsk/total- -net/total- ---paging-- ---system--
usr sys idl wai hiq siq| read writ| recv send| in out | int csw
0 0 99 0 0 0|2224B 118k| 0 0 | 0 5B| 157 614
0 1 99 0 0 0| 0 0 |1914B 0 | 0 0 | 318 820
1 0 99 0 0 0| 0 196k| 208B 0 | 0 0 | 271 789
1 1 98 0 0 0| 0 0 | 0 0 | 0 0 | 292 772

  (2)通过 top 找到 D 状态的进程。

  (3)通过 pidstat 找到具体进程的 I/O 状态,-d 参数输出 I/O 使用情况,-p 参数指定具体进程号:pidstat -d -p 4344 1 3

  (4)若上述 pidstat 找不到具体 I/O 原因,可以去掉 -p 参数,查看所有进程。

  (5)通过 strace -p / perf record (top) -g 动态追踪到具体进程中的某函数。

  僵尸进程分析

  既然僵尸进程是因为父进程没有回收子进程的资源而出现的,那么,也就是找出父进程的问题。

  (1)通过 pstree -aps 找出当前进程的父进程。// -a 表示输出命令行选项 p 表示 PID s 表示指定进程的父进程

  (2)查看父进程的代码,看看子进程结束的处理是否正确,比如有没有调用 wait() 或 waitpid() ,或是,有没有注册 SIGCHLD 信号的处理函数。

  

  

  

  

Linux性能优化从入门到实战:04 CPU篇:CPU使用率的更多相关文章

  1. Linux性能优化从入门到实战:01 Linux性能优化学习路线

      我通过阅读各种相关书籍,从操作系统原理.到 Linux内核,再到硬件驱动程序等等.   把观察到的性能问题跟系统原理关联起来,特别是把系统从应用程序.库函数.系统调用.再到内核和硬件等不同的层级贯 ...

  2. Linux性能优化从入门到实战:17 网络篇:网络基础

    网络模型 为了解决网络互联中异构设备的兼容性问题,并解耦复杂的网络包处理流程,国际标准化组织制定了开放式系统互联通信参考模型(Open System Interconnection Reference ...

  3. Linux性能优化从入门到实战:07 CPU篇:CPU性能优化方法

    性能优化方法论   动手优化性能之前,需要明确以下三个问题:   (1)如何评估性能优化的效果? 确定性能的量化指标.测试优化前的性能指标.测试优化后的性能指标.   量化指标的选择.至少要从应用程序 ...

  4. Linux性能优化从入门到实战:16 文件系统篇:总结磁盘I/O指标/工具、问题定位和调优

    (1)磁盘 I/O 性能指标 文件系统和磁盘 I/O 指标对应的工具 文件系统和磁盘 I/O 工具对应的指标 (2)磁盘 I/O 问题定位分析思路 (3)I/O 性能优化思路 Step 1:首先采用 ...

  5. Linux性能优化从入门到实战:09 内存篇:Buffer和Cache

      Buffer 是缓冲区,而 Cache 是缓存,两者都是数据在内存中的临时存储.   避免跟文中的"缓存"一词混淆,而文中的"缓存",则通指内存中的临时存储 ...

  6. Linux性能优化从入门到实战:03 CPU篇:CPU上下文切换

      linux操作系统是将CPU轮流分配给任务,分时执行的.而每次执行任务时,CPU需要知道CPU寄存器(CPU内置的内存)和程序计数器PC(CPU正在执行指令和下一条指令的位置)值,这些值是CPU执 ...

  7. Linux性能优化从入门到实战:15 文件系统篇:磁盘 I/O

    磁盘   磁盘是可以持久化存储的设备,按照存储介质来分类:   (1)机械磁盘(硬盘驱动器,Hard Disk Driver,HDD),主要由盘片和读写磁头组成,数据就存储在盘片的环状磁道中.在读写数 ...

  8. Linux性能优化从入门到实战:12 内存篇:Swap 基础

    内存资源紧张时,可能导致的结果 (1)OOM 杀死大内存CPU利用率又低的进程(系统内存耗尽的情况下才生效:OOM 触发的时机是基于虚拟内存,即进程在申请内存时,如果申请的虚拟内存加上服务器实际已用的 ...

  9. Linux性能优化从入门到实战:10 内存篇:如何利用Buffer和Cache优化程序的运行效率?

    缓存命中率   缓存命中率,是指直接通过缓存获取数据的请求次数,占所有数据请求次数的百分比,可以衡量缓存使用的好坏.命中率越高,表示使用缓存带来的收益越高,应用程序的性能也就越好.   实际上,缓存是 ...

随机推荐

  1. sh_02_第2个Python程序

    sh_02_第2个Python程序 print("hello")

  2. C# 创建临时文件(转帖)

    1. 在临时文件只能够创建一个临时文件并返回该文件的完整路径 // 在临时文件只能够创建一个临时文件并返回该文件的完整路径: // C:\Documents and Settings\YourName ...

  3. A - Biorhythms (第三周)

    A - Biorhythms 链接:https://vjudge.net/contest/154063#problem Description 人生来就有三个生理周期,分别为体力.感情和智力周期,它们 ...

  4. justify-content

    CSS3弹性布局内容对齐(justify-content)属性使用详解 内容对齐(justify-content)属性应用在弹性容器上,把弹性项沿着弹性容器的主轴线(main axis)对齐. 该操作 ...

  5. Day2 01 引用类型和值类型

    值类型:值类型变量,存储的是对象的值.给其赋值,会创建值的副本,修改任何一个副本,不会影响其他副本. int x = 5; int y = x;  //创建一个x的副本y  x把其自身的值传送给了y ...

  6. 使用自定义的tstring.h

    UNICODE   控制函数是否用宽字符版本_UNICODE 控制字符串是否用宽字符集 _T("") 根据上述定义来解释字符集 // 在tchar.h中 // tstring.h ...

  7. Redis 简介,安装,卸载

    一.Redis简介 redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(s ...

  8. PHP模拟请求和操作响应

    模拟请求 fsockopen <?php // 建立连接 $link = fsockopen('localhost', '80'); define('CRLF', "\r\n" ...

  9. java对接短信平台

    短信验证码目前是比较主流验证身份的一种方式,下面分享下我对接的几种短信平台 阿里云短信:https://api.alidayu.com/docs/api.htm?spm=a3142.7395905.4 ...

  10. Openstack_通用模块_Oslo_vmware 创建/删除 vCenter 虚拟机

    目录 目录 oslovmware Connect to vCenter Server Create VirtualMachine for vCenter 常用的虚拟机配置项 删除虚拟机 oslo.vm ...