目录
1 平均负载
1.1概念
平均负载是指单位时间内,系统处于 可运行状态 和 不可中断状态 的平均进程数,也就是平均活跃进程 数,它和 CPU 使用率并没有直接关系
- 可运行状态的进程,是指正在使用 CPU 或者正在等待 CPU 的进程,也就是我们常用 ps 命令看到 的,处于 R 状态(Running 或 Runnable)的进程。
- 不可中断状态的进程则是正处于内核态关键流程中的进程,并且这些流程是不可打断的,比如最常 见的是等待硬件设备的 I/O 响应(),也就是我们在 ps 命令中看到的 D 状态(Uninterruptible Sleep,也称为 Disk Sleep)的进程。正常情况下,不可中断状态在很短时间内就会结束,短时的不可中断状态进程,这个状态一般可以忽略。
平均负载其实就是平均活跃进程数。平均活跃进程数,直观上的理解就是单位时间内的活跃进程数。
1.2 uptime指令(检测平均负载)
查看机器的 启动时间、登录用户、平均负载等情况, 通常用于在线上应急或者技术攻关中,确定操作系 统的重启时间。
[root@iZwz97d32td9ocseu9tkn4Z sjp]# uptime
22:29:59 up 694 days, 11:27, 1 user, load average: 1.49, 0.41, 0.23
可以获取的信息是:
- 当前时间:22:29:59
- 系统已经运行的时间: 694 天 11:27
- 当前在线用户:1(开一个终端算一个用户)
- 系统平均负载:1.49 , 0.49, 0.23,为最近1分钟、5分钟、15分钟的系统负载情况。
如果每个CPU内核的当前活动进程数不大于3的话,那么系统的性能还算可以支持。
如果每个CPU内核的任务数大于5,那么这台机器的性能有严重问题。
1.3 负载分析
如何分析平均负载,比如当平均负载为2(有两个活跃的进程数) 的时候,意味着什么?
- 在只有 2 个 CPU 的系统上,意味着所有的 CPU 都刚好被完全占用。
- 在 4 个 CPU 的系统上,意味着 CPU 有 50% 的空闲。
- 而在只有 1 个 CPU 的系统中,则意味着有一半的进程竞争不到 CPU。
获取cpu信息
cat /proc/cpuinfo
获取cpu的核数
[root@iZwz97d32td9ocseu9tkn4Z sjp]# grep "model name" /proc/cpuinfo | wc -l
1
- 我的系统上的只有一个cpu,也就是单核cpu。
- 在cpu信息中,model name是用来描述cpu的名称,如果有多个cpu,则会有多个model name。
1.4 单核cpu负载分析
- load<0.7 说明系统很空闲,要考虑多部署一些服务
- 0.7<load<1 系统状态不错
- load ==1时,系统马上出来不过来了,需要查找原因
- load>5 ,系统已经非常繁忙了
1.5 不同时间内的load值分析
根据uptime命令中对 最近1分钟、5分钟、15分钟的系统负载情况进行分析
- 1分钟 load >5,5分钟 load <3,15分钟 load <1
短期内繁忙,中长期空闲,初步判断是一个抖动或者是拥塞前兆
- 1分钟 load >5,5分钟 load >3,15分钟 load <1
短期内繁忙,中期内紧张,很可能是一个拥塞的开始
- 1分钟 load >5,5分钟 load >5,15分钟 load >5
短中长期都繁忙,系统正在拥塞
- 1分钟 load 3,15分钟 load >5
短期内空闲,中长期繁忙,不用紧张,系统拥塞正在好转
平均负载高于 CPU 数量 70% 的时候,我们就该考虑分析排查负载高的问题了。一旦负载过高,就可 能导致进程响应变慢,进而影响服务的正常功能。
1.6 平均负载和cpu使用率的区别
平均负载
是指单位时间内,处于可运行状态和不可中断状态的进程数。所以,它不仅包括了正在使用 CPU 的进程,还包括等待 CPU 和等待 I/O 的进程。
CPU 使用率
是单位时间内 CPU 繁忙情况的统计,跟平均负载并不一定完全对应。比如:
- CPU 密集型进程,使用大量 CPU 会导致平均负载升高,此时这两者是一致的。
- I/O 密集型进程,等待 I/O 也会导致平均负载升高,但 CPU 使用率不一定很高;
- 大量等待 CPU 的进程调度也会导致平均负载升高,此时的 CPU 使用率也会比较高。
2. 压测命令
stress ,一个 Linux 系统压力测试工具,这里我们用作异常进程模拟平均负载升高的场景。
2.1 对cpu进行压力测试
stress -c N
让stress生成N个工作进程进行开方运算,以此对CPU产生负载。
2.2 对内存进行压力测试
stress -m N
让stress生成N个工作进程来占用内存。每个进程默认占用256M内存,但可以通过 --vm-bytes
来进行设置每个进程占用的内存。例如:
stress -m 3 --vm-bytes 300M
2.3对磁盘压力测试
对磁盘压力测试有两个参数:
stress -i N 会产生N个进程,每个进程反复调用sync()将内存上的内容写到硬盘上.
而 stress -d N 会产生N个进程,每个进程往当前目录中写入固定大小的临时文件,然后执行unlink操作删除该临时文件。 临时文件的大小默认为1G,但可以通过 --hdd-bytes 设置临时文件的大小。
2.4 同时对多项指标进行测试
stress支持同时对多个指标进行压力测试,只需要把上面的参数组合起来就行。
stress -c 4 -m 2 -d 1
3. 监测命令
3.1 mpstat(查看cpu的使用信息)
mpstat是Multiprocessor Statistics的缩写,是实时系统监控工具,此命令用于实时监控 系统CPU 的一些统计信息,这些信息存放在/proc/stat 文件中,在多核CPU系统里, 不但能查看所有CPU的平均使用信息,还能查看某个特定CPU的信息。
使用方式:mpstat [-P {cpu|ALL}] [internal [count]]
参数:
- -P {cpu l ALL} 表示监控哪个CPU, cpu在[0,cpu个数-1]中取值,ALL表示监控所有的cpu
- internal 相邻的两次采样的间隔时间
- count 采样的次数,count只能和internal一起使用
例子:检测所有的cpu信息,每2秒产生一次报告,一共产生3次。
[root@iZwz97d32td9ocseu9tkn4Z sjp]# mpstat -P ALL 2 3
Linux 3.10.0-957.21.3.el7.x86_64 (iZwz97d32td9ocseu9tkn4Z) 06/23/2023 _x86_64_ (1 CPU)
12:15:18 AM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
12:15:20 AM all 1.52 0.00 2.03 0.00 0.00 0.00 0.00 0.00 0.00 96.45
12:15:20 AM 0 1.52 0.00 2.03 0.00 0.00 0.00 0.00 0.00 0.00 96.45
12:15:20 AM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
12:15:22 AM all 2.02 0.00 2.02 0.00 0.00 0.00 0.00 0.00 0.00 95.96
12:15:22 AM 0 2.02 0.00 2.02 0.00 0.00 0.00 0.00 0.00 0.00 95.96
Average: CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
Average: all 1.77 0.00 2.03 0.00 0.00 0.00 0.00 0.00 0.00 96.20
Average: 0 1.77 0.00 2.03 0.00 0.00 0.00 0.00 0.00 0.00 96.20
各个参数的含义:
3.2 pidstat
是一个常用的进程性能分析工具,用来实时查看 进程的 CPU、内存、I/O 以及上下文 切换等性能指标。
使用方式:pidstat [option] interval [count]
参数:
- -u:表示查看cpu相关的性能指标
- -w:表示查看上下文切换情况,要想查看每个进程的详细情况,要加上-w
- -t:查看线程相关的信息,默认是进程的;常与-w结合使用(cpu的上下文切换包括进程的切换、线程 的切换、中断的切换)
- -d:展示磁盘 I/O 统计数据
- -p:指明进程号
- -r: 输出内存信息
例子:
[root@iZwz97d32td9ocseu9tkn4Z build]# pidstat -urd -p 31207
Linux 3.10.0-957.21.3.el7.x86_64 (iZwz97d32td9ocseu9tkn4Z) 06/23/2023 _x86_64_ (1 CPU)
12:45:55 AM UID PID %usr %system %guest %CPU CPU Command
12:45:55 AM 0 31207 0.00 0.00 0.00 0.00 0 test
12:45:55 AM UID PID minflt/s majflt/s VSZ RSS %MEM Command
12:45:55 AM 0 31207 0.00 0.00 172076 1948 0.10 test
12:45:55 AM UID PID kB_rd/s kB_wr/s kB_ccwr/s Command
12:45:55 AM 0 31207 0.00 0.00 0.00 test
其中:
输出cpu使用信息 -u
12:49:24 AM UID PID %usr %system %guest %CPU CPU Command
12:49:24 AM 0 31207 0.00 0.00 0.00 0.00 0 test
- %usr:用户层任务正在使用的CPU百分比(with or without nice priority ,NOT include time spent running a virtual processor)
- %system:系统层正在执行的任务的CPU使用百分比
- %guest :运行虚拟机的CPU占用百分比
- %CPU :所有的使用的CPU的时间百分比 CPU 处理器数量 Command 命令
输出内存使用信息 -r
12:45:55 AM UID PID minflt/s majflt/s VSZ RSS %MEM Command
12:45:55 AM 0 31207 0.00 0.00 172076 1948 0.10 test
- PID :进程号
- minflt/s:每秒次缺页错误次数(minor page faults),每次缺页错误次数意即虚拟内存地址映射成物理内存地址产生的page fault次数
- majflt/s :每秒主缺页错误次数(major page faults),当虚拟内存地址映射成物理内存 地址时,相应的page在swap中,这样的page fault为major page fault,一般在内存使用紧张时产 生
- VSZ:该进程使用的虚拟内存(以kB为单位)
- RSS:该进程使用的物理内存(以kB为单位)
- %MEM:当前任务使用的有效内存的百分比
- Command:任务的命令名
输出磁盘I/O使用信息 -d
12:45:55 AM UID PID kB_rd/s kB_wr/s kB_ccwr/s Command
12:45:55 AM 0 31207 0.00 0.00 0.00 test
- PID :进程号
- kB_rd/s :每秒此进程从磁盘读取的千字节数
- kB_wr/s:此进程已经或者将要写入磁盘的每秒千字节数
- kB_ccwr/s :由任务取消的写入磁盘的千字节数
- Command:命令的名字
上下文切换信息 -w
[root@iZwz97d32td9ocseu9tkn4Z ~]# pidstat -w 1 1
Linux 3.10.0-957.21.3.el7.x86_64 (iZwz97d32td9ocseu9tkn4Z) 06/24/2023 _x86_64_ (1 CPU)
12:39:42 AM UID PID cswch/s nvcswch/s Command
12:39:43 AM 0 1 0.97 0.00 systemd
12:39:43 AM 0 3 8.74 0.00 ksoftirqd/0
12:39:43 AM 0 9 52.43 0.00 rcu_sched
- PID:PID号
- cswch/s :每秒自动上下文切换
- nvcswch/s :每秒非自愿的上下文切换
- Command :命令
自动上下文切换和非自愿上下文切换的区别:
- 所谓自愿上下文切换,是指进程无法获取所需资源,导致的上下文切换。比如说, I/O、内存等系 统资源不足时,就会发生自愿上下文切换。
- 而非自愿上下文切换,则是指进程由于 时间片已到等原因,被系统强制调度,进而发生的上下文切换。比如说,大量进程都在争抢 CPU 时,就容易发生非自愿上下文切换。
4.cpu上下文切换
4.1什么是cpu上下文切换
所谓的上下文切换,就是把上一个任务的寄存器和计数器保存起来,然后加载新任务的寄存器和计数 器,最后跳转到新 任务的位置开始执行新任务。
可以分为:进程上下文切换,线程上下文切换,以及中断上下文切换。
4.2系统调用上下文切换
linux进程既可以在用户空间运行,也可以在内核态运行。
- 当它在用户空间运行时,被称为进程的用户态
- 当它进入进入内核空间的时候,被称为进程的内核态
进程的用户态向内核态转变的过程:
- 从用户态到内核态的转变过程,需要通过系统调用来完成 CPU 寄存器里原来的指令位置是在用户态。
- 但是为了执行内核态代码,需要先把用户态的位置保存起 来,然后 寄存器更新为内核态指令的新位置。最后跳转到内核态运行内核任务。
- 当系统调用结束后,CPU 寄存器需要恢复原来保存的用户态位置,然后再切换到用户空间,继续运行进 程。一次系统调用发生了两次 CPU 上下文切换!
系统调用过程中对用户态的资源没有任何影响,也不会切换进程,所以也称为特权模式切换。
4.3 进程上下文切换
进程是由内核来管理和调度的,所以进程的切换只发生在内核态。进程的上下文不仅包括了虚拟内存、 栈、全局变量等用户空间的资源,还包括了内核堆栈、寄存器等内核空间的状态。
- 进程的上下文切换在保存当前进程的内核状态和 CPU 寄存器之前,需要先把该进程的虚拟内存、栈等保 存下来;
- 而加载了下一进程的内核态后再刷新进程的虚拟内存映射关系和用户栈,刷新虚拟内存映射就 涉及到 TLB 快表 (虚拟地址缓存),因此会影响内存的访问速度。
单次进程上下文切换的 CPU 时间在几十纳秒到数微秒之间。特别是在进程上下文切换次数较多的情况 下,很容易导致 CPU 将大量时间耗费在寄存器、内核栈以及虚拟内存等资源的保存和恢复上,进而影响 cpu 的实际使用率。
进程上下文切换的原因:
- 为了保证所有进程可以得到公平调度,CPU 时间被划分为一段段的时间片,这些时间片再被轮流 分配给各个进程。这样,当某个进程的时间片耗尽了,就会被系统挂起,切换到其它正在等待 CPU 的进 程运行。(被动切换)
- 进程在系统资源不足,这个时候进程也会被挂起,并由系统调度其他进程运行。(主动切换)
- 当进程通过睡眠函数 sleep 这样的方法将自己主动挂起时,自然也会重新调度
- 当有优先级更高的进程运行时,为了保证高优先级进程的运行,当前进程会被挂起,由高优先级 进程来运行。
- 发生硬件中断时,CPU 上的进程会被中断挂起,转而执行内核中的中断服务程序。
4.3线程上下文切换
线程切换有两种可能:
- 前后两个线程属于不同进程。此时,因为资源不共享,所以切换过程就跟进程上下文切换是一样。
- 前后两个线程属于同一个进程。此时,因为虚拟内存是共享的,所以在切换时,虚拟内存这些资源就 保持不动,只需要切换线程的私有数据、寄存器等不共享的数据。
4.4中断上下文切换
- 为了快速响应硬件的事件,中断处理会打断进程的正常调度和执行,转而调用中断处理程序,响应设备事件。而在打断其他进程时,就需要将进程当前的状态保存下来,这样在中断结束后,进程仍然可以从 原来的状态恢复运行。
- 跟进程上下文不同,中断上下文切换并不涉及到进程的用户态。因为需要先进入内核,才能对内核态进入切换,所以中断上下文只包括内核态中断服务程序 执行所必需的状态,包括 CPU 寄存器、内核堆栈、硬件中断参数等
4.5 vmstat(查看上下文切换)
vmstat 可以查询系统的上下文切换情况。此命令显示关于 内核线程、虚拟内存、 磁盘I/O 、陷阱和CPU占用率的统计信息。
vmstat 2 :每隔 2 秒钟进行查询
各个参数含义:
- r(Running or Runnable)是就绪队列的长度,也就是正在运行和等待 CPU 的进程数。
- b(Blocked)则是处于不可中断睡眠状态的进程数。
- buff:是I/O系统存储的磁盘块文件的元数据的统计信息。
- cache:是操作系统用来缓存磁盘数据的缓冲区,操作系统会自动一调节这个参数,在内存紧张时 操作系统会减少cache的占用空间来保证其他进程可用。
- si和so较大时,说明系统频繁使用交换区,应该查看操作系统的内存是否够用。
- bi和bo代表I/O活动,根据其大小可以知道磁盘I/O的负载情况。
- in(interrupt)则是每秒中断的次数。
- cs:参数表示线程环境的切换次数,此数据太大时表明线程的同步机制有问题。
实战
1.CPU密集型检测分析
1.模拟一个cpu使用率100%的场景,再使用检测工具定位问题。
stress -c 1 --timeout 600 #运行600秒后结束
2.在第二个终端运行uptime查看负载。
[root@iZwz97d32td9ocseu9tkn4Z ~]# uptime
22:18:45 up 695 days, 11:16, 3 users, load average: 0.74, 0.21, 0.11
[root@iZwz97d32td9ocseu9tkn4Z ~]# uptime 3 3
22:18:50 up 695 days, 11:16, 3 users, load average: 1.32, 0.34, 0.15
[root@iZwz97d32td9ocseu9tkn4Z ~]# uptime 3 3
22:19:22 up 695 days, 11:16, 3 users, load average: 3.06, 0.89, 0.34
[root@iZwz97d32td9ocseu9tkn4Z ~]# uptime
22:19:25 up 695 days, 11:16, 3 users, load average: 3.45, 1.01, 0.38
[root@iZwz97d32td9ocseu9tkn4Z ~]# uptime
22:19:33 up 695 days, 11:17, 3 users, load average: 3.98, 1.16, 0.44
3. 第三个终端运行 mpstat 判断负载升高的原因是什么
%usr接近100%,说明用户态的cpu使用接近100%,iowait只有0,说明平均负载的升高是由cpu原因导致的。
4.使用pidstat查看哪个进程导致cpu使用率为100%。
2.多线程模拟上下文切换的检测分析
1.使用sysbench 来模拟系统多线程调度切换的情况。
#以10个线程运行5分钟的基准测试,模拟多线程切换的问题
sysbench --num-threads=10 --max-time=300 --max-requests=10000000 --test=threads run
2.使用vmstat查看
- r列:就绪队列增长到了8,甚至10,远远超过系统cpu数 1,所以肯定会有大量的cpu竞争。
- cs列:上下文切换次数从之前的 10000多 上升到 100多万
- us(user)和 sy(system)列:这两列的 CPU 使用率加起来上升到了 100%,其中系统 CPU 使 用率,也就是 sy 列高达 82%,说明 CPU 主要是被内核占用了.
综合这几个指标,我们可以知道,系统的就绪队列过长,也就是正在运行和等待 CPU 的进程数过多, 导致了大量的上下文切换,而上下文切换又导致了系统 CPU 的占用率升高
3.使用pidstat -u查看cpu的使用情况
[root@iZwz97d32td9ocseu9tkn4Z ~]# pidstat -u 1 1
Linux 3.10.0-957.21.3.el7.x86_64 (iZwz97d32td9ocseu9tkn4Z) 06/24/2023 _x86_64_ (1 CPU)
01:09:24 AM UID PID %usr %system %guest %CPU CPU Command
01:09:26 AM 0 6232 0.00 0.68 0.00 0.68 0 OpenDebugAD7
01:09:26 AM 0 10505 0.00 0.68 0.00 0.68 0 AliYunDun
01:09:26 AM 0 10524 0.00 0.68 0.00 0.68 0 AliYunDunMonito
01:09:26 AM 1000 12287 0.00 0.68 0.00 0.68 0 OpenDebugAD7
01:09:26 AM 0 12674 17.01 68.71 0.00 85.71 0 sysbench
01:09:26 AM 0 12695 0.68 2.72 0.00 3.40 0 pidstat
从 pidstat 的输出你可以发现,CPU 使用率的升高果然是 sysbench 导致的,它的 CPU 使用率已经达到了85%。
#-w是查看进程的切换次数,-wt是查看线程的切换次数
[root@iZwz97d32td9ocseu9tkn4Z ~]# pidstat -wt 1 1
Linux 3.10.0-957.21.3.el7.x86_64 (iZwz97d32td9ocseu9tkn4Z) 06/24/2023 _x86_64_ (1 CPU)
12:47:24 AM UID TGID TID cswch/s nvcswch/s Command
Average: 0 - 11392 9857.51 88706.96 |__sysbench
Average: 0 - 11393 12134.07 82109.16 |__sysbench
Average: 0 - 11397 10506.23 84509.89 |__sysbench
Average: 0 - 11398 15011.36 76247.25 |__sysbench
Average: 0 - 11399 12129.67 85352.38 |__sysbench
Average: 0 - 11400 11706.96 82725.64 |__sysbench
Average: 0 - 11401 13775.82 80100.00 |__sysbench
Average: 0 - 11402 13310.62 78448.35 |__sysbench
Average: 0 - 11403 14151.28 78148.72 |__sysbench
Average: 0 - 11405 8510.62 89108.42 |__sysbench
可见,系统的上下文切换过多是由sysbench的子线程过多引起的,然后,我们再根据上下文切换的类型,再做具体分析。比方说:
- 自愿上下文切换变多了,说明进程都在等待资源,有可能发生了 I/O 等其他问题;
- 非自愿上下文切换变多了,说明进程都在被强制调度,也就是都在争抢 CPU,说明 CPU 的确成了瓶 颈;