CPU性能排查总结

CPU性能排查总结

重要指标说明

平均负载

使用uptime命令查看平均负载结果如下

# uptime
 04:13:44 up 3 days, 1 min,  2 users,  load average: 0.05, 0.05, 0.05
# 其中load average:0.05, 0.05, 0.05
# 分别表示过去1分钟,5分钟,15分钟的平均负载
# man uptime解释如下:
# System load averages is the average number of processes that are either in a runnable or uninterruptable state.  A process in
# a  runnable  state is either using the CPU or waiting to use the CPU.  A process in uninterruptable state is waiting for some
# I/O access, eg waiting for disk.  The averages are taken over the three time intervals.  Load averages are not normalized for
# the number of CPUs in a system, so a load average of 1 means a single CPU system is loaded all the time while on a 4 CPU sys‐
# tem it means it was idle 75% of the time.

平均负载指的是单位时间内,系统处于可运行状态不可中断状态的平均进程数,也就是平均活跃进程数。可运行状态指的是正在使用CPU或正在等待CPU的进程,也就是ps命令中查看的处于R(Running或Runnable)状态的进程,不可中断状态的进程则处于内核态关键流程中的进程,并且这些流程是不可打断的,比如常见的等待硬件设备的IO响应,也就是ps命令查看的D(Uninterruptible Sleep,也成为Disk Sleep)状态,不可中断状态实际上是系统对进程和硬件设备的一种保护机制。

CPU使用率

CPU使用类别有:

  • 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时间的百分比:
c p u 使 用 率 = 1 − 空 闲 时 间 / 总 c p u 时 间 cpu使用率=1-空闲时间/总cpu时间 cpu使=1/cpu

平均负载指的是单位时间内,处于可运行状态和不可运行状态的进程数,所以不仅包括了正在使用CPU的进程,还包括等待CPU和等待I/O的进程,而CPU使用率是单位时间内CPU繁忙情况的统计,跟平均负载不一定完全对应。如:

  • CPU密集型,使用大量CPU资源导致平均负载升高,此时两者是一致的
  • I/O密集型,等待I/O会导致平均负载升高,但CPU使用率不一定很高
  • 大量等待CPU的进程调度也会导致平均负载升高,此时CPU使用率也会较高

CPU 使用率是最直观和最常用的系统性能指标,更是我们在排查性能问题时,通常会关注的第一个指标。所以我们更要熟悉它的含义,尤其要弄清楚用户(%user)、Nice(%nice)、系统(%system) 、等待 I/O(%iowait) 、中断(%irq)以及软中断(%softirq)这几种不同 CPU 的使用率。比如说:

  • 用户 CPU 和 Nice CPU 高,说明用户态进程占用了较多的 CPU,所以应该着重排查进程的性能问题。
  • 系统 CPU 高,说明内核态占用了较多的 CPU,所以应该着重排查内核线程或者系统调用的性能问题。
  • I/O 等待 CPU 高,说明等待 I/O 的时间比较长,所以应该着重排查系统存储是不是出现了 I/O 问题。
  • 软中断和硬中断高,说明软中断或硬中断的处理程序占用了较多的 CPU,所以应该着重排查内核中的中断服务程序。

碰到 CPU 使用率升高的问题,你可以借助 top、pidstat 等工具,确认引发 CPU 性能问题的来源;再使用 perf 等工具,排查出引起性能问题的具体函数

CPU上下文切换

Linux是一个多任务操作系统,它支持远大于CPU数量的任务同时运行,这些任务并非真正同时运行,而是因为系统在很短时间内,将CPU轮流分配给他们,造成多任务同时运行的错觉。而在每个任务运行前,需要系统事先帮它设置好CPU寄存器和程序计数器(Program Counter,PC)

CPU寄存器是CPU内置的容量很小,但是速度极快的内存,而程序计数器则是用来存储CPU正在执行的指令位置,或即将执行的下一条指令位置,他们都是CPU在运行任何任务前必须依赖的环境,因此也叫CPU上下文

CPU上下文切换就是把前一个任务的CPU上下文(CPU寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务

根据任务的不同CPU上下文切换可以分为几个不同的场景,也就是进程上下文切换线程上下文切换以及中断上下文切换

不管是那种上下文切换,需要注意的是:

  • CPU 上下文切换,是保证 Linux 系统正常工作的核心功能之一,一般情况下不需要我们特别关注。
  • 过多的上下文切换,会把 CPU 时间消耗在寄存器、内核栈以及虚拟内存等数据的保存和恢复上,从而缩短进程真正运行的时间,导致系统的整体性能大幅下降。
进程上下文切换

Linux按照特权等级,把进程的运行空间分为内核空间和用户空间,分别对应CPU特权等级的Ring 0 和 Ring 3。

  • 内核空间(Ring 0)具有最高权限,可以直接访问所有资源
  • 用户空间(Ring 3)只能访问受限资源,不能直接访问内存等硬件设备,必须通过系统调用陷入到内核中,才能访问这些特权资源

也就是进程可以在用户空间运行,也可以在内核空间运行,进程在用户空间运行时,称为进程的用户态,陷入内核空间的时候,被称为进程的内核态

从用户态到内核态的切换需要通过系统调用来完成,比如当查看文件内容时,就需要多次系统调用来完成,先调用open()打开文件,然后调用read()读取文件内容,并调用write()将内容写到标准输出,最后再调用close文件

而系统调用的过程中会将CPU寄存器里原来用户态的指令位置保存起来,接着为了执行内核态代码,CPU寄存器需要更新为内核态指令的新位置,最后再跳转到内核态运行内核任务。

系统调用结束后,CPU寄存器需要恢复原来保存的用户态,再切换到用户空间,继续运行进程,所以,一次系统调用,实际上发生了2此CPU上下文切换

不过,需要注意的是,系统调用过程中,并不会涉及到虚拟内存等进程用户态的资源,也不会切换进程。这跟我们通常所说的进程上下文切换是不一样的:

  • 进程上下文切换,是指从一个进程切换到另一个进程运行。
  • 而系统调用过程中一直是同一个进程在运行

所以,**系统调用过程通常称为特权模式切换,而不是上下文切换。**但实际上,系统调用过程中,CPU 的上下文切换还是无法避免的。

进程是由内核来管理和调度的,进程的切换只能发生在内核态。所以,进程的上下文不仅包括了虚拟内存、栈、全局变量等用户空间的资源,还包括了内核堆栈、寄存器等内核空间的状态。

因此,进程的上下文切换就比系统调用时多了一步:在保存当前进程的内核状态和 CPU 寄存器之前,需要先把该进程的虚拟内存、栈等保存下来;而加载了下一进程的内核态后,还需要刷新进程的虚拟内存和用户栈。

保存上下文和恢复上下文并不是免费的需要内核再CPU上运行才能完成

每次上下文切换都需要几十纳秒到数微秒的 CPU 时间。这个时间还是相当可观的,特别是在进程上下文切换次数较多的情况下,很容易导致 CPU 将大量时间耗费在寄存器、内核栈以及虚拟内存等资源的保存和恢复上,进而大大缩短了真正运行进程的时间。

另外,我们知道, Linux 通过 TLB(Translation Lookaside Buffer)来管理虚拟内存到物理内存的映射关系。当虚拟内存更新后,TLB 也需要刷新,内存的访问也会随之变慢。特别是在多处理器系统上,缓存是被多个处理器共享的,刷新缓存不仅会影响当前处理器的进程,还会影响共享缓存的其他处理器的进程。

进程切换时才需要切换上下文,换句话说,只有在进程调度的时候,才需要切换上下文。Linux 为每个 CPU 都维护了一个就绪队列,将活跃进程(即正在运行和正在等待 CPU 的进程)按照优先级和等待 CPU 的时间排序,然后选择最需要 CPU 的进程,也就是优先级最高和等待 CPU 时间最长的进程来运行。

触发进程调度到CPU运行的场景:

  1. 为了保证所有进程可以得到公平调度,CPU 时间被划分为一段段的时间片,这些时间片再被轮流分配给各个进程。这样,当某个进程的时间片耗尽了,就会被系统挂起,切换到其它正在等待 CPU 的进程运行。
  2. 进程在系统资源不足(比如内存不足)时,要等到资源满足后才可以运行,这个时候进程也会被挂起,并由系统调度其他进程运行。
  3. 当进程通过睡眠函数 sleep 这样的方法将自己主动挂起时,自然也会重新调度。
  4. 当有优先级更高的进程运行时,为了保证高优先级进程的运行,当前进程会被挂起,由高优先级进程来运行。
  5. 发生硬件中断时,CPU 上的进程会被中断挂起,转而执行内核中的中断服务程序。
线程上下文切换

线程与进程最大的区别在于,线程是调度的基本单位,而进程则是资源拥有的基本单位。所谓内核中的任务调度,实际上的调度对象是线程;而进程只是给线程提供了虚拟内存、全局变量等资源。

  • 当进程只有一个线程,可以认为进程等于线程
  • 当进程有多个线程,这些线程会共享相同的虚拟内存和全局变量等资源,这些资源再上下文切换时是不需要修改的
  • 线程也有自己的私有数据,这些在上下文切换时是需要保存的。

当线程发生上下文切换就分为两种情况:

  1. 属于不同进程,此时由于资源不共享,所以切换过程就跟进程上下文切换是一样的
  2. 属于同一个进程,此时虚拟内存是共享的,在切换时,虚拟内存这些资源不动,只需要切换线程的私有数据,寄存器等不共享的数据

同为上下文切换,可以看出同进程内的线程切换要比多进程间的切换消耗更少的资源,这也是多线程代替多进程的一个优势

中断上下文切换

为了快速响应硬件事件,中断程序会打断进程的正常调度和执行,转而调用中断处理程序,响应设备事件,而在打断其他进程时,就需要将进程当前的状态保存下来,这样在中断结束后,进程仍然可以从原来的状态中恢复运行,跟进程上下文不同,中断上下文切换不涉及进程的用户态,所以中断过程打断了一个正处于用户态的进程,也不需要保存和恢复这个进程的虚拟内存,全局变量等用户态资源,中断上下文,其实只包括内核态终端服务程序执行所必须的状态,包括CPU寄存器,内核堆栈,硬件中断等参数。

对同一个 CPU 来说,中断处理比进程拥有更高的优先级,所以中断上下文切换并不会与进程上下文切换同时发生。同样道理,由于中断会打断正常进程的调度和执行,所以大部分中断处理程序都短小精悍,以便尽可能快的执行结束。

另外,跟进程上下文切换一样,中断上下文切换也需要消耗 CPU,切换次数过多也会耗费大量的 CPU,甚至严重降低系统的整体性能。所以,当你发现中断次数过多时,就需要注意去排查它是否会给你的系统带来严重的性能问题。

cswch与nvcswch
  • cswch ,表示每秒自愿上下文切换(voluntary context switches)的次数,

  • nvcswch ,表示每秒非自愿上下文切换(non voluntary context switches)的次数。

这两个指标可以通过pidstat -w查看,其中:

  • 自愿上下文切换,是指进程无法获取所需资源,导致的上下文切换。比如说, I/O、内存等系统资源不足时,就会发生自愿上下文切换。
  • 非自愿上下文切换,则是指进程由于时间片已到等原因,被系统强制调度,进而发生的上下文切换。比如说,大量进程都在争抢 CPU 时,就容易发生非自愿上下文切换。

关于上下文切换的瓶颈分析:

  • 自愿上下文切换变多了,说明进程都在等待资源,有可能发生了 I/O 等其他问题;
  • 非自愿上下文切换变多了,说明进程都在被强制调度,也就是都在争抢 CPU,说明 CPU 的确成了瓶颈;
  • 中断次数变多了,说明 CPU 被中断处理程序占用,还需要通过查看watch -d "cat /proc/interrupts" 文件来分析具体的中断类型。

软中断

中断其实是一种异步的事件处理机制,可以提高系统的并发处理能力。由于中断处理程序会打断其他进程的运行,所以,为了减少对正常进程运行调度的影响,中断处理程序就需要尽可能快地运行。如果中断本身要做的事情不多,那么处理起来也不会有太大问题;但如果中断要处理的事情很多,中断服务程序就有可能要运行很长时间。特别是,中断处理程序在响应中断时,还会临时关闭中断。这就会导致上一次中断处理完成之前,其他中断都不能响应,也就是说中断有可能会丢失。

Linux将中断处理过程分为上半部和下半部:

  • 上半部用来快速处理中断,它在中断禁止模式下运行,主要处理跟硬件紧密相关的或时间敏感的工作。
  • 下半部用来延迟处理上半部未完成的工作,通常以内核线程的方式运行。

例如:网卡接收到数据包后,会通过硬件中断的方式,通知内核有新的数据到了。这时,内核就应该调用中断处理程序来响应它。对上半部来说,既然是快速处理,其实就是要把网卡的数据读到内存中,然后更新一下硬件寄存器的状态(表示数据已经读好了),最后再发送一个软中断信号,通知下半部做进一步的处理。而下半部被软中断信号唤醒后,需要从内存中找到网络数据,再按照网络协议栈,对数据进行逐层解析和处理,直到把它送给应用程序。

所以,这两个阶段你也可以这样理解:

  • 上半部直接处理硬件请求,也就是我们常说的硬中断,特点是快速执行;
  • 下半部则是由内核触发,也就是我们常说的软中断,特点是延迟执行。

实际上,上半部会打断 CPU 正在执行的任务,然后立即执行中断处理程序。而下半部以内核线程的方式执行,并且每个 CPU 都对应一个软中断内核线程,名字为 “ksoftirqd/CPU 编号”,比如说, 0 号 CPU 对应的软中断内核线程的名字就是 ksoftirqd/0。不过要注意的是,软中断不只包括了刚刚所讲的硬件设备中断处理程序的下半部,一些内核自定义的事件也属于软中断,比如内核调度和 RCU 锁(Read-Copy Update 的缩写,RCU 是 Linux 内核中最常用的锁之一)等。

查看中断信息:

  • /proc/softirqs 提供了软中断的运行情况,Linux 中的软中断包括网络收发、定时、调度、RCU 锁等各种类型
  • /proc/interrupts 提供了硬中断的运行情况。
# cat /proc/softirqs  | awk '{print $1,$2,$3,$4} '
CPU0 CPU1 CPU2 CPU3
HI: 0 2 0
TIMER: 52776094 26302251 0
NET_TX: 54647 3 0
NET_RX: 3299726 839641 0
BLOCK: 241695 358027 0
BLOCK_IOPOLL: 0 0 0
TASKLET: 10020 103 0
SCHED: 6887846 4866827 0
HRTIMER: 0 0 0
RCU: 7585671 5658226 0
# 第一,要注意软中断的类型,也就是这个界面中第一列的内容。从第一列你可以看到,软中断包括了 10 个类别,分别对应不同的工作类型。比如 NET_RX 表示网络接收中断,而 NET_TX 表示网络发送中断。
# 第二,要注意同一种软中断在不同 CPU 上的分布情况,也就是同一行的内容。正常情况下,同一种中断在不同 CPU 上的累积次数应该差不多。比如这个界面中,NET_RX 在 CPU0 和 CPU1 上的中断次数基本是同一个数量级,相差不大。

CPU性能分析常用工具

  • mpstat:常用的多核 CPU 性能分析工具,用来实时查看每个 CPU 的性能指标,以及所有 CPU 的平均指标。

  • pidstat:一个常用的进程性能分析工具,用来实时查看进程的 CPU、内存、I/O 以及上下文切换等性能指标。

  • uptime:查看系统平均负载,可以结合pidstat,mpstat进一步分析排查

  • vmstat:查看上下文切换和中断次数异常,可以结合pidstat进一步排查

  • perf top/record/report -g:查看系统和进程的CPU使用状况

  • execsnoop:监控进程调用,系统默认没有

  • dstat:查看系统整体状态,可以结合pidstat,strace,perf进一步排查

  • sar -n DEV 1:查看网络情况,后续可以再结合tcpdump进一步排查

  • watch -d cat /proc/softirqs || cat /proc/interrupts:监控中断状态

  • pstree:查看进程之间的父子关系

mpstat

mpstat 是一个常用的多核 CPU 性能分析工具,用来实时查看每个 CPU 的性能指标,以及所有 CPU 的平均指标。

# 1. 显示所有CPU的指标,并在间隔5秒输出一组数据
# mpstat -P ALL 5 1
Linux 3.10.0-957.el7.x86_64 (localhost.localdomain)     07/29/2020      _x86_64_        (2 CPU)

04:34:45 AM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
04:34:50 AM  all    0.30    0.00    0.60    0.00    0.00    0.00    0.00    0.00    0.00   99.09
04:34:50 AM    0    0.20    0.00    0.60    0.00    0.00    0.20    0.00    0.00    0.00   99.00
04:34:50 AM    1    0.40    0.00    0.80    0.00    0.00    0.00    0.00    0.00    0.00   98.80

Average:     CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
Average:     all    0.30    0.00    0.60    0.00    0.00    0.00    0.00    0.00    0.00   99.09
Average:       0    0.20    0.00    0.60    0.00    0.00    0.20    0.00    0.00    0.00   99.00
Average:       1    0.40    0.00    0.80    0.00    0.00    0.00    0.00    0.00    0.00   98.80
# 输出完毕后会计算这段时间内的平均值,也就是Average



pidstat

pidstat 是一个常用的进程性能分析工具,用来实时查看进程的 CPU、内存、I/O 以及上下文切换等性能指标。

# 1. 间隔5秒后输出一组数据
# pidstat -u 5 1
Linux 3.10.0-957.el7.x86_64 (localhost.localdomain)     07/29/2020      _x86_64_        (2 CPU)

04:36:32 AM   UID       PID    %usr %system  %guest    %CPU   CPU  Command
04:36:37 AM     0      2607    0.00    0.20    0.00    0.20     1  sshd
04:36:37 AM     0      2628    0.00    0.40    0.00    0.40     1  bash
04:36:37 AM  1000     30315    0.40    0.20    0.00    0.60     1  mysqld
04:36:37 AM     0    114958    0.20    0.00    0.00    0.20     0  pidstat

Average:      UID       PID    %usr %system  %guest    %CPU   CPU  Command
Average:        0      2607    0.00    0.20    0.00    0.20     -  sshd
Average:        0      2628    0.00    0.40    0.00    0.40     -  bash
Average:     1000     30315    0.40    0.20    0.00    0.60     -  mysqld
Average:        0    114958    0.20    0.00    0.00    0.20     -  pidstat
# 输出完毕后会计算这段时间内的平均值,也就是Average
# 2. w查看上下文切换相关数据,t表示输出线程信息,默认只显示进程信息
# pidstat -wt 5 1
Linux 3.10.0-957.el7.x86_64 (localhost.localdomain)     07/29/2020      _x86_64_        (2 CPU)

06:02:08 AM   UID      TGID       TID   cswch/s nvcswch/s  Command
06:02:13 AM     0         3         -      1.31      0.00  ksoftirqd/0
06:02:13 AM     0         -         3      1.31      0.00  |__ksoftirqd/0
06:02:13 AM     0         7         -      2.43      0.00  migration/0
06:02:13 AM     0         -         7      2.43      0.00  |__migration/0
06:02:13 AM     0         9         -     40.67      0.00  rcu_sched
...

Average:      UID      TGID       TID   cswch/s nvcswch/s  Command
Average:        0         3         -      1.31      0.00  ksoftirqd/0
Average:        0         -         3      1.31      0.00  |__ksoftirqd/0
Average:        0         7         -      2.43      0.00  migration/0
Average:        0         -         7      2.43      0.00  |__migration/0
Average:        0         9         -     40.67      0.00  rcu_sched
Average:        0         -         9     36.01      0.00  |__rcu_sched
...

# UID: The real user identification number of the task being monitored. 
# USER: The name of the real user owning the task being monitored. 
# PID: The identification number of the task being monitored.
# cswch/s: Total  number of voluntary context switches the task made per second.  A voluntary context switch occurs when a task blocks because it requires a resource that is unavailable.表示每秒自愿上下文切换(voluntary context switches)的次数
# nvcswch/s: Total number of non voluntary context switches the task made per second.  A involuntary  context  switch  takes place when a task executes for the duration of its time slice and then is forced to relinquish the processor.非自愿上下文切换,则是指进程由于时间片已到等原因,被系统强制调度,进而发生的上下文切换。
# Command:The command name of the task.

# -d 展示 I/O 统计数据,-p 指定进程号,间隔 1 秒输出 3 组数据
# pidstat -d -p 4344 1 3
06:38:50      UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s iodelay  Command
06:38:51        0      4344      0.00      0.00      0.00       0  app
06:38:52        0      4344      0.00      0.00      0.00       0  app
06:38:53        0      4344      0.00      0.00      0.00       0  app
# kB_rd/s:Number of kilobytes the task has caused to be read from disk per second.每秒读的 KB 数
# kB_wr/s:Number of kilobytes the task has caused, or shall cause to be written to disk per second.每秒写的 KB 数
# kB_ccwr/s:Number  of  kilobytes  whose writing to disk has been cancelled by the task. This may occur when the task truncates some dirty pagecache. In this case, some IO which another task has been accounted for will not be happening.任务已取消对磁盘的写入的千字节数。当任务truncates一些脏页面时,可能会发生这种情况。在这种情况下,其他任务已经考虑的一些IO将不会发生。

vmstat

vmstat 是一个常用的系统性能分析工具,主要用来分析系统的内存使用情况,也常用来分析 CPU 上下文切换和中断的次数。

# 1. 每隔5秒输出1组数据
# vmstat 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 1  0  19712 158884      0 2959688    0    0     6    31   71   51 11  1 88  0  0
 0  0  19712 158984      0 2959704    0    0     0     0  258  413  0  1 99  0  0
 0  0  19712 159020      0 2959704    0    0     0     0  251  413  0  1 99  0  0
 0  0  19712 158876      0 2959704    0    0     0     0  258  420  0  1 99  0  0
 0  0  19712 158504      0 2959704    0    0     0     0  261  420  0  1 99  0  0
# 其中第一组数据是系统运行至今的平均数据
# 第二组开始时每隔5s的系统资源情况
#   Procs
#       r: The number of runnable processes (running or waiting for run time).正在运行和等待 CPU 的进程数。
#       b: The number of processes in uninterruptible sleep.处于不可中断睡眠进程数
#   Memory
#       swpd: the amount of virtual memory used.已被使用的虚拟内存
#       free: the amount of idle memory.空闲内存
#       buff: the amount of memory used as buffers.被用于buffer的内存
#       cache: the amount of memory used as cache.被用于cache的内存
#   Swap
#       si: Amount of memory swapped in from disk (/s).
#       so: Amount of memory swapped to disk (/s).
#   IO
#       bi: Blocks received from a block device (blocks/s).
#       bo: Blocks sent to a block device (blocks/s).
#   System
#       in: The number of interrupts per second, including the clock.每秒中断数
#       cs: The number of context switches per second.每秒上下文切换数
#   CPU
#       These are percentages of total CPU time.
#       us: Time spent running non-kernel code.  (user time, including nice time)
#       sy: Time spent running kernel code.  (system time)
#       id: Time spent idle.  Prior to Linux 2.5.41, this includes IO-wait time.
#       wa: Time spent waiting for IO.  Prior to Linux 2.5.41, included in idle.
#       st: Time stolen from a virtual machine.  Prior to Linux 2.6.11, unknown.

perf

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

# -g表示开启调用关系采样
# perf top -g
Samples: 833  of event 'cpu-clock', Event count (approx.): 97742399
Overhead  Shared Object       Symbol
   7.28%  perf                [.] 0x00000000001f78a4
   4.72%  [kernel]            [k] vsnprintf
   4.32%  [kernel]            [k] module_get_kallsym
   3.65%  [kernel]            [k] _raw_spin_unlock_irqrestore
...
# 输出结果中,第一行包含三个数据,分别是采样数(Samples)、事件类型(event)和事件总数量(Event count)。
# 比如这个例子中,perf 总共采集了 833 个 CPU 时钟事件,而总事件数则为 97742399。
# 第一列 Overhead ,是该符号的性能事件在所有采样中的比例,用百分比来表示。
# 第二列 Shared ,是该函数或指令所在的动态共享对象(Dynamic Shared Object),如内核、进程名、动态链接库名、内核模块名等。
# 第三列 Object ,是动态共享对象的类型。比如 [.] 表示用户空间的可执行程序、或者动态链接库,而 [k] 则表示内核空间。
# 最后一列 Symbol 是符号名,也就是函数名。当函数名未知时,用十六进制的地址来表示。

# perf record 则提供了保存数据的功能
# perf record -g # 按Ctrl+C终止采样
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.452 MB perf.data (6093 samples) ]
# # 展示类似于perf top的报告
# perf report 

pstree

pstree 就可以用树状形式显示所有进程之间的关系

# pstree | grep stress
        |-docker-containe-+-php-fpm-+-php-fpm---sh---stress
        |         |-3*[php-fpm---sh---stress---stress]

top

常用的查看进程状态的工具

top - 07:42:47 up 3 days,  3:30,  3 users,  load average: 0.37, 0.34, 0.18
Tasks: 127 total,   1 running, 126 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.2 us,  0.9 sy,  0.0 ni, 98.9 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  3861512 total,   120708 free,   836384 used,  2904420 buff/cache
KiB Swap:  2097148 total,  2077436 free,    19712 used.  2704060 avail Mem

   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
  2607 root      20   0  158856   6164   4732 S   4.3  0.2   5:45.27 sshd
 50252 root      20   0  113180   1588   1332 S   4.3  0.0   0:00.79 bash
 49990 root      20   0  319260  11780   4780 S   2.7  0.3   0:11.46 urlgrabber-ext-
 30315 mysql     20   0 1810792 620164   9112 S   1.0 16.1  53:35.23 mysqld
 49194 root      20   0  583032  27888   9604 S   0.3  0.7   0:11.04 yum
     1 root      20   0  128148   4332   2680 S   0.0  0.1   1:02.07 systemd
# S 列(也就是 Status 列)表示进程的状态,有如下选项:
# |-- 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 的缩写,表示进程处于暂停或者跟踪状态。向一个进程发送 SIGSTOP 信号,它就会因响应这个信号变成暂停状态(Stopped);再向它发送 SIGCONT 信号,进程又会恢复运行(如果进程是终端里直接启动的,则需要你用 fg 命令,恢复到前台运行)。而当你用调试器(如 gdb)调试一个进程时,在使用断点中断进程后,进程就会变成跟踪状态,这其实也是一种特殊的暂停状态,只不过你可以用调试器来跟踪并按需要控制进程的运行。
# |-- X,也就是 Dead 的缩写,表示进程已经消亡,所以你不会在 top 或者 ps 命令中看到它。

这里补充一个孤儿进程和僵尸进程的区别

  • 孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

  • 僵尸进程:正常情况下,当一个进程创建了子进程后,它应该通过系统调用 wait()或者 waitpid() 等待子进程结束,回收子进程的资源;而子进程在结束时,会向它的父进程发送 SIGCHLD 信号,所以,父进程还可以注册 SIGCHLD 信号的处理函数,异步回收资源。如果父进程没这么做,或是子进程执行太快,父进程还没来得及处理子进程状态,子进程就已经提前退出,那这时的子进程就会变成僵尸进程。换句话说,父亲应该一直对儿子负责,善始善终,如果不作为或者跟不上,都会导致“问题少年”的出现。通常,僵尸进程持续的时间都比较短,在父进程回收它的资源后就会消亡;或者在父进程退出后,由 init 进程回收后也会消亡。一旦父进程没有处理子进程的终止,还一直保持运行状态,那么子进程就会一直处于僵尸状态。大量的僵尸进程会用尽 PID 进程号,导致新进程不能创建,所以这种情况一定要避免。

ps

查看当前程序的快照信息


# 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 表示可中断睡眠状态,
# D 表示不可中断睡眠状态,我们在前面刚学过,
# s 表示这个进程是一个会话的领导进程
# + 表示前台进程组。
# 进程组表示一组相互关联的进程,比如每个子进程都是父进程所在组的成员;而会话是指共享同一个控制终端的一个或多个进程组。

dstat

可以同时查看 CPU 和 I/O 这两种资源的使用情况

# 间隔1秒输出10组数据
# dstat 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 stl| read  writ| recv  send|  in   out | int   csw
  0   0  96   4   0|1219k  408k|   0     0 |   0     0 |  42   885
  0   0   2  98   0|  34M    0 | 198B  790B|   0     0 |  42   138
  0   0   0 100   0|  34M    0 |  66B  342B|   0     0 |  42   135
  0   0  84  16   0|5633k    0 |  66B  342B|   0     0 |  52   177
  0   3  39  58   0|  22M    0 |  66B  342B|   0     0 |  43   144
  0   0   0 100   0|  34M    0 | 200B  450B|   0     0 |  46   147
  0   0   2  98   0|  34M    0 |  66B  342B|   0     0 |  45   134
  0   0   0 100   0|  34M    0 |  66B  342B|   0     0 |  39   131
  0   0  83  17   0|5633k    0 |  66B  342B|   0     0 |  46   168
  0   3  39  59   0|  22M    0 |  66B  342B|   0     0 |  37   134

sar

sar 可以用来查看系统的网络收发情况,还有一个好处是,不仅可以观察网络收发的吞吐量(BPS,每秒收发的字节数),还可以观察网络收发的 PPS,即每秒收发的网络帧数。

# -n DEV 表示显示网络收发的报告,间隔1秒输出一组数据
$ sar -n DEV 1
15:03:46        IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s   %ifutil
15:03:47         eth0  12607.00   6304.00    664.86    358.11      0.00      0.00      0.00      0.01
15:03:47      docker0   6302.00  12604.00    270.79    664.66      0.00      0.00      0.00      0.00
15:03:47           lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
15:03:47    veth9f6bbcd   6302.00  12604.00    356.95    664.66      0.00      0.00      0.00      0.05
# 第一列:表示报告的时间。
# 第二列:IFACE 表示网卡。
# 第三、四列:rxpck/s 和 txpck/s 分别表示每秒接收、发送的网络帧数,也就是  PPS。
# 第五、六列:rxkB/s 和 txkB/s 分别表示每秒接收、发送的千字节数,也就是  BPS。

CPU排查套路

  • 根据指标找工具
    image
    • 工具对应的指标
      image
      • 性能分析路径图
        image

参考文档

  • 《极客时间:Linux性能优化实战》,作者:倪鹏飞
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值