此时可以看到是stress占用了很高的 CPU 。
IO 问题排查我们使用stress -i 1来模拟 IO 瓶颈问题,即死循环执行 sync 刷盘操作: ? uptime:使用uptime查看此时系统负载:
$ watch -d uptime...,load average: 1.06, 0.58, 0.37mpstat:查看此时 IO 消耗,但是实际上我们发现这里 CPU 基本都消耗在了 sys 即系统消耗上 。
Average:CPU%usr%nice%sys %iowait%irq%soft%steal%guest%gnice%idleAverage:all0.330.0012.640.130.000.000.000.000.0086.90Average:00.000.0099.001.000.000.000.000.000.000.00Average:10.000.000.330.000.000.000.000.000.0099.67IO 无法升高的问题:
iowait 无法升高的问题,是因为案例中 stress 使用的是 sync()系统调用,它的作用是刷新缓冲区内存到磁盘中 。对于新安装的虚拟机,缓冲区可能比较小,无法产生大的 IO 压力,这样大部分就都是系统调用的消耗了 。所以,你会看到只有系统 CPU 使用率升高 。解决方法是使用 stress 的下一代 stress-ng,它支持更丰富的选项,比如stress-ng -i 1 --hdd 1 --timeout 600(--hdd 表示读写临时文件) 。
Average:CPU%usr%nice%sys %iowait%irq%soft%steal%guest%gnice%idleAverage:all0.250.000.4426.220.000.000.000.000.0073.09Average:00.000.001.0298.980.000.000.000.000.000.00pidstat:同上(略)
可以看出 CPU 的 IO 升高导致系统平均负载升高 。我们使用pidstat查找具体是哪个进程导致 IO 升高的 。
top:这里使用 top 依旧是最方面的查看综合参数,可以得出stress是导致 IO 升高的元凶 。
pidstat 没有 iowait 选项:可能是 centos 默认的sysstat太老导致,需要升级到 11.5.5 之后的版本才可用 。
进程数过多问题排查进程数过多这个问题比较特殊,如果系统运行了很多进程超出了 CPU 运行能,就会出现等待 CPU 的进程 。使用stress -c 24来模拟执行 24 个进程(我的 CPU 是 8 核) uptime:使用uptime查看此时系统负载:
$ watch -d uptime...,load average: 18.50, 7.13, 2.84mpstat:同上(略)
pidstat:同上(略)
可以观察到此时的系统处理严重过载的状态,平均负载高达 18.50 。
top:我们还可以使用top命令查看此时Running状态的进程数,这个数量很多就表示系统正在运行、等待运行的进程过多 。
总结通过以上问题现象及解决思路可以总结出:
- 平均负载高有可能是 CPU 密集型进程导致的
- 平均负载高并不一定代表 CPU 使用率高,还有可能是 I/O 更繁忙了
- 当发现负载高的时候,你可以使用 mpstat、pidstat 等工具,辅助分析负载的来源
CPU 上下文切换CPU 上下文:CPU 执行每个任务都需要知道任务从哪里加载、又从哪里开始运行,也就是说,需要系统事先帮它设置好 CPU 寄存器和程序计数器(Program Counter,PC)包括 CPU 寄存器在内都被称为 CPU 上下文 。
CPU 上下文切换:CPU 上下文切换,就是先把前一个任务的 CPU 上下文(也就是 CPU 寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务 。
CPU 上下文切换:分为进程上下文切换、线程上下文切换以及中断上下文切换 。
进程上下文切换从用户态切换到内核态需要通过系统调用来完成,这里就会发生进程上下文切换(特权模式切换),当切换回用户态同样发生上下文切换 。
一般每次上下文切换都需要几十纳秒到数微秒的 CPU 时间,如果切换较多还是很容易导致 CPU 时间的浪费在寄存器、内核栈以及虚拟内存等资源的保存和恢复上,这里同样会导致系统平均负载升高 。
linux 为每个 CPU 维护一个就绪队列,将 R 状态进程按照优先级和等待 CPU 时间排序,选择最需要的 CPU 进程执行 。这里运行进程就涉及了进程上下文切换的时机:
- 进程时间的耗尽 。
- 进程在系统资源不足(内存不足) 。
- 进程主动sleep 。
- 有优先级更高的进程执行 。
- 硬中断发生 。
- 当进程只有一个线程时,可以认为进程就等于线程 。
- 当进程拥有多个线程时,这些线程会共享相同的虚拟内存和全局变量等资源 。这些资源在上下文切换时是不需要修改的 。
- 线程也有自己的私有数据,比如栈和寄存器等,这些在上下文切换时也是需要保存的 。
