Linux性能优化笔记--002 CPU篇
Linux性能分析 CPU
四个方向的第一个方向 CPU,本文分为四个篇章:分别为基础篇,案例篇,套路篇,答疑篇
基础篇
平均负载
平均负载是指单位时间内,系统处于可运行状态和不可中断状态的平均进程数,也就是平均活跃
进程数,它和 CPU 使用率并没有直接关系。

1.所谓可运行状态的进程,是指正在使用 CPU 或者正在等待 CPU 的进程,
也就是我们常用 ps 命令看到的,处于 R 状态(Running 或 Runnable)的进程。
2.不可中断状态的进程则是正处于内核态关键流程中的进程,并且这些流程是不可打断的,
比如最常见的是等待硬件设备的 I/O 响应,也就是我们在 ps 命令中看到的 D 状态
不可中断举例: 一个向磁盘写数据的进程 在磁盘回复前 为了避免数据不一致 这个进程是不可被打断。
平均负载是单位时间平均活跃进程数量
最理想的状态是 一个核运行一个进程 这样每个CPU核都充分运行了
比如:
2个CPU有两个进程 则完全占用
4个CPU有两个进程 则闲置50%的CPU
1个CPU则 有一半的进程竞争不到CPU
通过grep 和 wc 计算核的数量 然后通过uptime看平均负载来判断系统是否过载
三个时间长度的平均负载分析场景
1分钟 5 分钟 15分钟
1.相差不大 则系统负载平稳
2.1分钟远远小于15分钟 负载减少
3.1分钟远远大于15分钟 负载增加
例子:
这里我再举个例子,假设我们在一个单 CPU 系统上看到平均负载为 1.73,0.60,7.98,
那么说明在过去 1 分钟内,系统有 73% 的超载,
而在 15 分钟内,有 698% 的超载,从整体趋势来看,系统的负载在降低。
当平均负载高于 CPU 数量 70% 的时候,你就应该分析排查负载高的问题了。一旦负载过高,就可能导致进程响应变慢,进而影响服务的正常功能。
延伸指令:
1.uptime
02:34:03 up 2 days, 20:14, 1 user, load average: 0.63, 0.83, 0.88
02:34:03 //当前时间
up 2 days, 20:14 //系统运行时间
1 user //正在登录用户数
而最后三个数字呢,依次则是过去 1 分钟、5 分钟、15 分钟的平均负载(Load Average)。
2.grep和wc
$ grep 'model name' /proc/cpuinfo | wc -l
2 //核数量
这段代码的功能是使用 grep 命令在 /proc/cpuinfo 文件中查找包含字符串 'model name' 的行,
并通过管道将结果传递给 wc -l 命令进行行数统计。最后的输出结果是2,
表示找到了2行包含 'model name' 的内容。
CPU使用率
平均负载是指单位时间内,处于可运行状态和不可中断状态的进程数。
所以,它不仅包括了正在使用 CPU 的进程,还包括等待 CPU 和等待 I/O 的进程。
而 CPU 使用率,是单位时间内 CPU 繁忙情况的统计,跟平均负载并不一定完全对应。
比如:
1.CPU 密集型进程,使用大量 CPU 会导致平均负载升高,此时这两者是一致的;
CPU密集型代表使用CPU较多 CPU要持续运算
2.I/O 密集型进程,等待 I/O 也会导致平均负载升高,但 CPU 使用率不一定很高;
IO密集型代表进程多在阻塞 等待 也会让负载升高 但是使用率不一定高
3.大量等待 CPU 的进程调度也会导致平均负载升高,此时的 CPU 使用率也会比较高。
主要区别就是 活跃的进程 代表了平均负载 而使用CPU的进程 才是CPU使用率
活跃的进程不一定一直使用CPU
平均负载案例
工具介绍:
1.stress
一个Linux压测工具 可以用于生成进程
2.sysstat
包含了常用的Linux性能工具 用来监控分析系统性能。
mpstat 是一个常用的多核 CPU 性能分析工具,用来实时查看每个 CPU 的性能指标,
以及所有 CPU 的平均指标。 用于核的查看
pidstat 是一个常用的进程性能分析工具,用来实时查看进程的 CPU、内存、I/O
以及上下文切换等性能指标。 用于进程的查看
场景1:
$ stress --cpu 1 --timeout 600
这段代码的功能是使用stress工具模拟高负载场景。
其中,--cpu 1表示使用一个CPU核心进行基准测试,--timeout 600表示测试持续的时间为600秒。
# -d 参数表示高亮显示变化的区域
$ watch -d uptime
..., load average: 1.00, 0.75, 0.39
# -P ALL 表示监控所有CPU,后面数字5表示间隔5秒后输出一组数据
$ mpstat -P ALL 5
Linux 4.15.0 (ubuntu) 09/22/18 _x86_64_ (2 CPU)
13:30:06 CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
13:30:11 all 50.05 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 49.95
13:30:11 0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
13:30:11 1 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
# 间隔5秒后输出一组数据 5 1
$ pidstat -u 5 1
13:37:07 UID PID %usr %system %guest %wait %CPU CPU Command
13:37:12 0 2962 100.00 0.00 0.00 0.00 100.00 1 stress
通过场景1 使用stress 在CPU1上 进行模拟 先使用 watch -d uptime 来观察平均负载
使用mpstat 观察CPU使用率 和平均负载进行比较 观察CPU密集型进程的影响
最后使用pidstat 观察是哪个进程
场景2:
首先还是运行 stress 命令,但这次模拟 I/O 压力,即不停地执行 sync(sync 同步即 IO):
$ stress -i 1 --timeout 600
$ stress-ng -i 1 --hdd 1 --timeout 600
而—hdd 则表示读写临时文件
-i 1表示使用1个进程调用sync()
# 显示所有CPU的指标,并在间隔5秒输出一组数据
$ mpstat -P ALL 5 1
Linux 4.15.0 (ubuntu) 09/22/18 _x86_64_ (2 CPU)
13:41:28 CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
13:41:33 all 0.21 0.00 12.07 32.67 0.00 0.21 0.00 0.00 0.00 54.84
13:41:33 0 0.43 0.00 23.87 67.53 0.00 0.43 0.00 0.00 0.00 7.74
13:41:33 1 0.00 0.00 0.81 0.20 0.00 0.00 0.00 0.00 0.00 98.99
发现CPU的系统CPU使用率不高 但是iowait高 说明是iowait引起了平均负载的升高
场景3:
开启八个进程 这时候平均负载为8是正常的
$ stress -c 8 --timeout 600
$ uptime
..., load average: 7.97, 5.93, 3.02
运行mpstat观察各核的CPU使用率
11:57:55 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
11:58:00 PM all 99.70 0.00 0.30 0.00 0.00 0.00 0.00 0.00 0.00 0.00
11:58:00 PM 0 99.60 0.00 0.40 0.00 0.00 0.00 0.00 0.00 0.00 0.00
11:58:00 PM 1 99.80 0.00 0.20 0.00 0.00 0.00 0.00 0.00 0.00 0.00
运行pidstat观察进程的CPU使用率
Average: UID PID %usr %system %guest %wait %CPU CPU Command
Average: 999 9395 0.20 0.00 0.00 0.00 0.20 - mysqld
Average: 0 321656 0.20 0.00 0.00 0.00 0.20 - AliYunDun
Average: 0 321669 0.40 0.00 0.00 0.00 0.40 - AliYunDunMonito
Average: 0 340973 24.85 0.00 0.00 75.35 24.85 - stress
Average: 0 340974 24.85 0.00 0.00 75.15 24.85 - stress
Average: 0 340975 24.65 0.00 0.00 75.35 24.65 - stress
Average: 0 340976 24.85 0.20 0.00 74.95 25.05 - stress
Average: 0 340977 24.65 0.00 0.00 75.15 24.65 - stress
Average: 0 340978 24.85 0.00 0.00 75.35 24.85 - stress
Average: 0 340979 25.05 0.00 0.00 74.95 25.05 - stress
Average: 0 340980 24.65 0.20 0.00 74.95 24.85 - stress
Average: 0 341186 0.00 0.20 0.00 0.60 0.20 - pidstat
观察可以发现 每个核基本跑满了 八个进程 所以平均负载为8 每个核都是百分百运行。
8个stress进程 每个的CPU负载为25% 均分两个核 每个进程75%时间在等待
上下文切换
CPU 寄存器,是 CPU 内置的容量小、但速度极快的内存。而程序计数器,则是用来存储 CPU 正在执行的指令位置、或者即将执行的下一条指令位置。它们都是 CPU 在运行任何任务前,必须的依赖环境,因此也被叫做 CPU 上下文。 程序执行的本质及为内存中加载数据和指令到CPU的寄存器进行运算 即使进程没有运行,多个进程竞争CPU也会导致CPU负载很高
根据任务的不同,CPU上下文切换分为:
1.进程上下文切换
2.线程上下文切换
3.中断上下文切换
进程上下文切换:
1.系统调用造成的上下文切换
进程运行在用户空间和内核空间 分别称为用户态和内核态
用户态到内核态的转换通过系统调用完成
系统调用过程中存在上下文切换
CPU--用户态
系统调用---将CPU寄存器内容暂存---加载内核态指令
系统调用结束 切回用户态

系统调用的上下文切换指的是特权模式切换 但实际上CPU的上下文切换还是无法避免的
2.进程间上下文切换
进程1 --- 保存进程1上下文----加载进程2上下文---进程2

进程上下文切换时机:
1.时间片耗尽
2.系统资源不足
3.sleep函数主动挂起
4.优先级抢占
5.硬件中断 执行中断服务程序
线程上下文切换
线程是调度的基本单位 进程是资源拥有的基本单位
1.同进程下线程的上下文切换 不需要切换共享资源 仅切换私有数据 寄存器等
2.不同进程下上下文切换 需要切换资源
这可以看做是多线程比多进程的一个优势
中断上下文切换
中断会打断进程的正常调度和运行 进行中断处理程序
中断的上下文切换和进程上下文切换不同,中断上下文仅包含内核态中断服务程序执行的
必要条件包括CPU寄存器 内核堆栈 硬件中断参数等
中断上下午切换的优先级>进程
当中断次数过多,需要去排查性能问题
上下文切换分析方法
工具介绍:
目前(mpstat pidstat)
vmstat 用于分析系统的内存使用情况 也常常用来分析CPU上下文切换和中断次数
pidstat -w 加上w可以查看上下文切换情况
pidstat -wt 查看进程和线程的上下文切换情况
pidstat -w -u -u代表输出CPU情况
sysbench 是一个多线程的基准测试工具,一般用来评估不同系统参数下的数据库负载情况。
# 每隔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
0 0 0 7005360 91564 818900 0 0 0 0 25 33 0 0 100 0 0
cs(context switch)是每秒上下文切换的次数。
in(interrupt)则是每秒中断的次数。
r(Running or Runnable)是就绪队列的长度,也就是正在运行和等待 CPU 的进程数。
b(Blocked)则是处于不可中断睡眠状态的进程数。
# 每隔5秒输出1组数据
$ pidstat -w 5
Linux 4.15.0 (ubuntu) 09/23/18 _x86_64_ (2 CPU)
08:18:26 UID PID cswch/s nvcswch/s Command
08:18:31 0 1 0.20 0.00 systemd
08:18:31 0 8 5.40 0.00 rcu_sched
...
cswch ,表示每秒自愿上下文切换(voluntary context switches)的次数
nvcswch ,表示每秒非自愿上下文切换(non voluntary context switches)的次数。
1.使用vmstat查看上下文切换和中断等情况
2.使用pidstat -w 查看进程的切换情况
3.使用pidstat -wt 查看线程的的切换情况
4.到此可以确定上下文切换的源头问题
5.在确定中断上升的原因
那就是从 /proc/interrupts 这个只读文件中读取。
/proc 实际上是 Linux 的一个虚拟文件系统,用于内核空间与用户空间之间的通信。
/proc/interrupts 就是这种通信机制的一部分,提供了一个只读的中断使用情况。
6.watch -d cat /proc/interrupts
这个数值其实取决于系统本身的 CPU 性能。在我看来,如果系统的上下文切换次数比较稳定,
那么从数百到一万以内,都应该算是正常的。但当上下文切换次数超过一万次,
或者切换次数出现数量级的增长时,就很可能已经出现了性能问题。
1.自愿上下文切换变多了,说明进程都在等待资源,有可能发生了 I/O 等其他问题;
2.非自愿上下文切换变多了,说明进程都在被强制调度,也就是都在争抢 CPU,说明 CPU 的确成了瓶颈;
3.中断次数变多了,说明 CPU 被中断处理程序占用,还需要通过查看 /proc/interrupts 文件来分析具体的中断类型。
结合前两节,首先通过uptime查看系统负载,然后使用mpstat结合pidstat来初步判断到底是cpu计算量大还是进程争抢过大或者是io过多,接着使用vmstat分析切换次数,以及切换类型,来进一步判断到底是io过多导致问题还是进程争抢激烈导致问题。

浙公网安备 33010602011771号