CPU和IO debug工具,方法,实践

从我球docs粘过来的,不想写两份,看着乱的,直接看最后的结论

Linux CPU 性能优化指南

uptime查看系统瓶颈负载

[root /home/user]# uptime 
13:11:01 up 888 days, 21:33,  8 users,  load average: 17.20, 14.85, 14.10

lscpu查看 CPU 信息:

[root@Tencent-SNG /home/user_00]# lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 32
On-line CPU(s) list: 0-31
Thread(s) per core: 2
Core(s) per socket: 8
Socket(s): 2
NUMA node(s): 2
Vendor ID: GenuineIntel
CPU family: 6
Model: 62
Stepping: 4
CPU MHz: 1999.917
BogoMIPS: 4000.92
Virtualization: VT-x
L1d cache: 32K
L1i cache: 32K
L2 cache: 256K
L3 cache: 20480K
NUMA node0 CPU(s): 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30
NUMA node1 CPU(s): 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31

cat /proc/cpuinfo查看每个 CPU 核的信息:

processor : 23
vendor_id : GenuineIntel
cpu family : 6
model : 62
model name : Intel(R) Xeon(R) CPU E5-2640 v2 @ 2.00GHz
stepping : 4
microcode : 0x416
cpu MHz : 1999.917
cache size : 20480 KB
physical id : 1
siblings : 16
core id : 3
cpu cores : 8
apicid : 39
initial apicid : 39
fpu : yes
fpu_exception : yes
cpuid level : 13
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm ida arat xsaveopt pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase smep erms
bogomips : 4000.92
clflush size : 64
cache_alignment : 64
address sizes : 46 bits physical, 48 bits virtual
power management:
 

系统平均负载升高的原因

系统平均负载:是处于可运行或不可中断状态的平均进程数。

 

一般来说,系统平均负载升高意味着 CPU 使用率上升。但是他们没有必然联系,CPU 密集型计算任务较多一般系统平均负载会上升,但是如果 IO 密集型任务较多也会导致系统平均负载升高但是此时的 CPU 使用率不一定高,可能很低因为很多进程都处于不可中断状态,等待 CPU 调度也会升高系统平均负载。

 

所以假如我们系统平均负载很高,但是 CPU 使用率不是很高,则需要考虑是否系统遇到了 IO 瓶颈,应该优化 IO 读写速度。

 

所以系统是否遇到 CPU 瓶颈需要结合 CPU 使用率,系统瓶颈负载一起查看

stress: 是一个施加系统压力和压力测试系统的工具,我们可以使用stress工具压测试 CPU,以便方便我们定位和排查 CPU 问题。

stress --cpu 8 --io 4 --vm 2 --vm-bytes 128M --timeout 10s

 

// --cpu 8:8个进程不停的执行sqrt()计算操作 
// --io 4:4个进程不同的执行sync()io操作(刷盘) 
// --vm 2:2个进程不停的执行malloc()内存申请操作 
// --vm-bytes 128M:限制1个执行malloc的进程申请内存大小 

uptime:使用uptime查看此时系统负载:

watch -d uptime
# -d 参数表示高亮显示变化的区域
mpstat:使用mpstat -P ALL 1则可以查看每一秒的 CPU 每一核变化信息,整体和top类似,好处是可以把每一秒(自定义)的数据输出方便观察数据的变化,
最终输出平均数据:
Average: CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
Average: all 17.75 0.00 0.58 0.09 0.00 0.04 0.00 0.00 0.00 81.54
Average: 0 54.43 0.00 1.01 0.00 0.00 0.51 0.00 0.00 0.00 44.05
Average: 1 31.30 0.00 0.00 0.00 0.00 0.25 0.00 0.00 0.00 68.45
Average: 2 23.16 0.00 1.02 0.00 0.00 0.00 0.00 0.00 0.00 75.83
Average: 3 35.84 0.00 0.75 0.00 0.00 0.00 0.00 0.00 0.00 63.41
Average: 4 30.90 0.00 1.51 0.00 0.00 0.00 0.00 0.00 0.00 67.59
Average: 5 24.75 0.00 0.25 0.00 0.00 0.00 0.00 0.00 0.00 75.00
Average: 6 20.10 0.00 1.53 0.00 0.00 0.00 0.00 0.00 0.00 78.37
Average: 7 36.87 0.00 0.25 0.00 0.00 0.00 0.00 0.00 0.00 62.88
Average: 8 36.09 0.00 1.00 0.00 0.00 0.00 0.00 0.00 0.00 62.91
Average: 9 18.53 0.00 0.25 0.00 0.00 0.00 0.00 0.00 0.00 81.22
Average: 10 23.29 0.00 1.27 1.52 0.00 0.25 0.00 0.00 0.00 73.67
Average: 11 14.68 0.00 1.01 0.00 0.00 0.00 0.00 0.00 0.00 84.30
Average: 12 44.11 0.00 0.50 0.25 0.00 0.00 0.00 0.00 0.00 55.14
Average: 13 18.16 0.00 0.26 0.00 0.00 0.00 0.00 0.00 0.00 81.59
Average: 14 53.27 0.00 0.75 1.01 0.00 0.00 0.00 0.00 0.00 44.97
Average: 15 29.44 0.00 0.51 0.00 0.00 0.00 0.00 0.00 0.00 70.05
Average: 16 4.01 0.00 1.00 0.00 0.00 0.25 0.00 0.00 0.00 94.74
Average: 17 0.50 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 99.50
Average: 18 4.59 0.00 0.51 0.00 0.00 0.26 0.00 0.00 0.00 94.64
Average: 19 0.75 0.00 0.50 0.00 0.00 0.00 0.00 0.00 0.00 98.75
Average: 20 4.27 0.00 0.50 0.25 0.00 0.00 0.00 0.00 0.00 94.97
Average: 21 0.76 0.00 0.25 0.00 0.00 0.00 0.00 0.00 0.00 98.99
Average: 22 4.03 0.00 0.25 0.00 0.00 0.00 0.00 0.00 0.00 95.72
Average: 23 1.25 0.00 0.25 0.00 0.00 0.00 0.00 0.00 0.00 98.50
Average: 24 7.75 0.00 0.50 0.00 0.00 0.00 0.00 0.00 0.00 91.75
Average: 25 1.25 0.00 0.50 0.00 0.00 0.00 0.00 0.00 0.00 98.25
Average: 26 3.78 0.00 0.76 0.00 0.00 0.25 0.00 0.00 0.00 95.21
Average: 27 5.54 0.00 0.50 0.00 0.00 0.00 0.00 0.00 0.00 93.95
Average: 28 25.63 0.00 0.75 0.00 0.00 0.00 0.00 0.00 0.00 73.62
Average: 29 4.28 0.00 0.25 0.00 0.00 0.00 0.00 0.00 0.00 95.47
Average: 30 4.03 0.00 0.25 0.00 0.00 0.00 0.00 0.00 0.00 95.72
Average: 31 1.26 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 98.74

 

pidstat:使用pidstat -u 1则是每隔 1 秒输出当前系统进程、CPU 数据:

 

03:53:24 PM UID PID %usr %system %guest %CPU CPU Command
03:53:25 PM 1100 26782 0.00 1.00 0.00 1.00 0 pidstat

03:53:25 PM UID PID %usr %system %guest %CPU CPU Command

03:53:26 PM UID PID %usr %system %guest %CPU CPU Command
03:53:27 PM 1100 23841 0.00 1.00 0.00 1.00 14 redis-server
03:53:27 PM 1100 26440 0.00 1.00 0.00 1.00 13 watch

 

 

IO 问题排查

我们使用stress -i 1来模拟 IO 瓶颈问题,即死循环执行 sync 刷盘操作:

uptime:使用uptime查看此时系统负载:

pidstat -u 1:查看进程和CPU的关系:

查看此时 IO 消耗,但是实际上我们发现这里 CPU 基本都消耗在了 sys 即系统消耗上。

04:04:00 PM UID PID %usr %system %guest %CPU CPU Command
04:04:01 PM 1100 23791 0.00 1.00 0.00 1.00 5 redis-server
04:04:01 PM 1100 27041 0.00 66.00 0.00 66.00 8 stress

04:04:01 PM UID PID %usr %system %guest %CPU CPU Command
04:04:02 PM 1100 23818 0.00 1.00 0.00 1.00 10 redis-server
04:04:02 PM 1100 23853 0.00 1.00 0.00 1.00 12 redis-server
04:04:02 PM 1100 27041 0.00 51.00 0.00 51.00 1 stress
^C

Average: UID PID %usr %system %guest %CPU CPU Command
Average: 104 465 0.00 0.16 0.00 0.16 - zabbix_agentd
Average: 104 469 0.00 0.04 0.00 0.04 - zabbix_agentd
Average: 1100 23781 0.04 0.00 0.00 0.04 - redis-server
Average: 1100 23791 0.04 0.08 0.00 0.12 - redis-server
Average: 1100 23801 0.04 0.08 0.00 0.12 - redis-server
Average: 1100 23811 0.08 0.04 0.00 0.12 - redis-server
Average: 1100 23818 0.08 0.08 0.00 0.16 - redis-server
Average: 1100 23831 0.00 0.04 0.00 0.04 - redis-server
Average: 1100 23841 0.04 0.04 0.00 0.08 - redis-server
Average: 1100 23853 0.04 0.08 0.00 0.12 - redis-server
Average: 1100 26369 0.04 0.04 0.00 0.08 - sshd
Average: 1100 27027 0.08 0.08 0.00 0.16 - watch
Average: 1100 27041 0.00 61.26 0.00 61.26 - stress
Average: 1100 27245 0.16 0.16 0.00 0.32 - pidstat
Average: 0 28227 0.08 0.00 0.00 0.08 - salt-minion

 

IO 无法升高的问题:iowait 无法升高的问题,是因为案例中 stress 使用的是 sync()系统调用,它的作用是刷新缓冲区内存到磁盘中。对于新安装的虚拟机,缓冲区可能比较小,无法产生大的 IO 压力,这样大部分就都是系统调用的消耗了。

所以,你会看到只有系统 CPU 使用率升高。解决方法是使用 stress 的下一代 stress-ng,它支持更丰富的选项,

比如stress-ng -i 1 --hdd 1 --timeout 600(--hdd 表示读写临时文件)。

进程数过多问题排查

进程数过多这个问题比较特殊,如果系统运行了很多进程超出了 CPU 运行能,就会出现等待 CPU 的进程。使用stress -c 24来模拟执行 24 个进程(我的 CPU 是 8 核)

uptime:使用uptime查看此时系统负载:

Every 2.0s: uptime Thu Aug 20 16:24:32 2020

16:24:32 up 352 days, 6:20, 3 users, load average: 19.73, 26.67, 16.67

 

load average 定义

linux系统中的Load对当前CPU工作量的度量。简单的说是进程队列的长度。

Load Average 就是一段时间 (1 分钟、5分钟、15分钟) 内平均 Load 。

通过系统命令"w"查看当前load average情况

load average值的含义

1) 单核处理器

假设我们的系统是单CPU单内核的,把它比喻成是一条单向马路,把CPU任务比作汽车。当车不多的时候,load <1;当车占满整个马路的时候 load=1;当马路都站满了,而且马路外还堆满了汽车的时候,load>1

2) 多核处理器

我们经常会发现服务器Load > 1但是运行仍然不错,那是因为服务器是多核处理器(Multi-core)。
假设我们服务器CPU是2核,那么将意味我们拥有2条马路,我们的Load = 2时,所有马路都跑满车辆。

什么样的Load average值要提高警惕

  • 0.7 < load < 1: 此时是不错的状态,如果进来更多的汽车,你的马路仍然可以应付。
  • load = 1: 你的马路即将拥堵,而且没有更多的资源额外的任务,赶紧看看发生了什么吧。
  • load > 5: 非常严重拥堵,我们的马路非常繁忙,每辆车都无法很快的运行

三种Load值,应该看哪个

通常我们先看15分钟load,如果load很高,再看1分钟和5分钟负载,查看是否有下降趋势。
1分钟负载值 > 1,那么我们不用担心,但是如果15分钟负载都超过1,我们要赶紧看看发生了什么事情。所以我们要根据实际情况查看这三个值。

通过以上问题现象及解决思路可以总结出:

  1. 平均负载高有可能是 CPU 密集型进程导致的
  2. 平均负载高并不一定代表 CPU 使用率高,还有可能是 I/O 更繁忙了
  3. 当发现负载高的时候,你可以使用 mpstat、pidstat 等工具,辅助分析负载的来源

CPU 上下文切换

CPU 上下文:CPU 执行每个任务都需要知道任务从哪里加载、又从哪里开始运行,也就是说,需要系统事先帮它设置好 CPU 寄存器和程序计数器(Program Counter,PC)包括 CPU 寄存器在内都被称为 CPU 上下文。

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

CPU 上下文切换:分为进程上下文切换线程上下文切换以及中断上下文切换

进程上下文切换

从用户态切换到内核态需要通过系统调用来完成,这里就会发生进程上下文切换(特权模式切换),当切换回用户态同样发生上下文切换。

一般每次上下文切换都需要几十纳秒到数微秒的 CPU 时间,如果切换较多还是很容易导致 CPU 时间的浪费在寄存器、内核栈以及虚拟内存等资源的保存和恢复上,这里同样会导致系统平均负载升高

Linux 为每个 CPU 维护一个就绪队列,将 R 状态进程按照优先级和等待 CPU 时间排序,选择最需要的 CPU 进程执行。这里运行进程就涉及了进程上下文切换的时机:

  1. 进程时间片耗尽、。
  2. 进程在系统资源不足(内存不足)。
  3. 进程主动sleep
  4. 有优先级更高的进程执行。
  5. 硬中断发生。

程序状态Status进程可运行状态R不可中断运行D(后续讲解 top 时会详细说明)

线程上下文切换

线程和进程:

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

所以线程上下文切换包括了 2 种情况:

  1. 不同进程的线程,这种情况等同于进程切换。
  2. 同进程的线程切换,只需要切换线程私有数据、寄存器等不共享数据。

中断上下文切换

中断处理会打断进程的正常调度和执行,转而调用中断处理程序,响应设备事件。而在打断其他进程时,就需要将进程当前的状态保存下来,这样在中断结束后,进程仍然可以从原来的状态恢复运行。

对同一个 CPU 来说,中断处理比进程拥有更高的优先级,所以中断上下文切换并不会与进程上下文切换同时发生。

由于中断会打断正常进程的调度和执行,所以大部分中断处理程序都短小精悍,以便尽可能快的执行结束。

查看系统上下文切换

vmstat:工具可以查看系统的内存、CPU 上下文切换以及中断次数:

vmstat 1

每隔1秒输出

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
7 0 5841756 9572216 1267008 77536432 0 0 0 32 0 0 7 1 90 2 0
5 0 5841756 9571100 1267008 77536464 0 0 0 12 17802 34742 19 1 80 0 0
5 0 5841756 9572048 1267008 77536496 0 0 0 184 18695 33860 18 1 81 0 0
5 0 5841756 9571952 1267008 77536496 0 0 0 16 19338 33878 18 1 82 0 0
23 0 5841756 9570660 1267008 77536520 0 0 0 0 20100 33165 18 1 82 0 0
5 0 5841756 9565284 1267008 77536528 0 0 0 180 16433 32761 18 1 81 0 0
5 0 5841756 9565648 1267008 77536528 0 0 0 8 15986 33122 18 1 82 0 0
6 0 5841756 9565652 1267008 77536536 0 0 0 0 22246 34068 17 0 82 0 0
6 0 5841756 9566364 1267008 77536544 0 0 0 0 23079 32930 18 1 81 0 0
5 0 5841756 9565328 1267008 77536544 0 0 0 16 16024 33362 19 1 81 0 0
6 0 5841756 9565188 1267008 77536560 0 0 0 212 46166 33554 18 1 81 0 0
5 0 5841756 9560856 1267008 77536600 0 0 0 104 23391 35549 19 1 80 0 0
5 0 5841756 9556824 1267008 77536648 0 0 0 12 17632 35415 18 1 81 0 0

 

cs:则为每秒的上下文切换次数。

in:则为每秒的中断次数。

r:就绪队列长度,正在运行或等待 CPU 的进程。

b:不可中断睡眠状态的进程数,例如正在和硬件交互。

pidstat:使用pidstat -w选项查看具体进程的上下文切换次数:

pidstat -w -p 12847 1

05:09:42 PM UID PID cswch/s nvcswch/s Command
05:09:43 PM 1103 12847 0.00 0.00 redis-shake.lin
05:09:44 PM 1103 12847 0.00 0.00 redis-shake.lin
05:09:45 PM 1103 12847 0.00 0.00 redis-shake.lin
05:09:46 PM 1103 12847 0.00 0.00 redis-shake.lin
05:09:47 PM 1103 12847 0.00 0.00 redis-shake.lin
05:09:48 PM 1103 12847 0.00 0.00 redis-shake.lin
05:09:49 PM 1103 12847 0.00 0.00 redis-shake.lin
05:09:50 PM 1103 12847 0.00 0.00 redis-shake.lin
05:09:51 PM 1103 12847 0.00 0.00 redis-shake.lin
05:09:52 PM 1103 12847 0.00 0.00 redis-shake.lin
05:09:53 PM 1103 12847 0.00 0.00 redis-shake.lin
05:09:54 PM 1103 12847 0.00 0.00 redis-shake.lin
05:09:55 PM 1103 12847 0.00 0.00 redis-shake.lin
05:09:56 PM 1103 12847 0.00 0.00 redis-shake.lin
05:09:57 PM 1103 12847 0.00 0.00 redis-shake.lin
05:09:58 PM 1103 12847 0.00 0.00 redis-shake.lin
05:09:59 PM 1103 12847 0.00 0.00 redis-shake.lin
05:10:00 PM 1103 12847 0.00 0.00 redis-shake.lin
05:10:01 PM 1103 12847 0.00 0.00 redis-shake.lin
05:10:02 PM 1103 12847 0.00 0.00 redis-shake.lin
^C
Average: 1103 12847 0.00 0.00 redis-shake.lin

其中cswch/snvcswch/s表示自愿上下文切换和非自愿上下文切换。

自愿上下文切换:是指进程无法获取所需资源,导致的上下文切换。比如说, I/O、内存等系统资源不足时,就会发生自愿上下文切换。

非自愿上下文切换:则是指进程由于时间片已到等原因,被系统强制调度,进而发生的上下文切换。比如说,大量进程都在争抢 CPU 时,就容易发生非自愿上下文切换

sysbench:  工具模拟上下文切换问题。

sysbench --threads=64 --time=300 threads run

--threads The total number of worker threads to create 1
--events Limit for total number of requests. 0 (the default) means no limit 0
--time Limit for total execution time in seconds. 0 means no limit 10

 

r b swpd free buff cache si so bi bo in cs us sy id wa st
26 0 5841744 9255128 1270316 77763360 0 0 0 508 18263 37040 17 1 81 1 0
6 0 5841744 9256272 1270316 77763376 0 0 0 168 17021 34756 18 1 81 0 0
5 2 5841744 9255840 1270316 77763376 0 0 0 260 17261 35007 18 1 81 0 0
6 0 5841744 9254856 1270316 77763392 0 0 0 288 20777 34043 17 1 81 1 0
19 0 5841744 9255128 1270316 77763392 0 0 0 224 19785 36637 18 1 81 0 0
6 1 5841744 9256336 1270316 77763416 0 0 0 440 25022 39895 19 1 78 1 0
5 0 5841744 9255384 1270316 77763424 0 0 0 660 19293 38188 18 1 79 2 0
5 1 5841744 9254296 1270316 77763464 0 0 0 744 17314 34473 18 1 80 1 0
7 0 5841744 9253780 1270316 77763480 0 0 0 256 17370 35138 18 1 80 1 0
5 0 5841744 9254532 1270316 77763488 0 0 0 304 16410 33680 18 1 81 1 0
5 0 5841744 9252040 1270316 77763488 0 0 0 232 17735 36256 18 1 81 1 0
23 1 5841744 9251476 1270316 77763504 0 0 0 272 23305 32490 18 1 81 0 0
5 2 5841744 9250552 1270316 77763504 0 0 0 1540 19532 36502 18 1 79 2 0
25 2 5841744 9249300 1270316 77763520 0 0 0 784 21877 171067 18 3 78 2 0
27 0 5841744 9247404 1270316 77763552 0 0 0 328 101351 1371878 21 34 45 0 0
16 0 5841744 9248992 1270316 77763552 0 0 0 236 95376 434604 20 37 42 0 0
22 0 5841744 9248152 1270316 77763568 0 0 0 208 83671 452288 21 34 45 0 0
21 1 5841744 9246976 1270316 77763600 0 0 0 212 108116 408126 20 37 43 0 0
28 0 5841744 9246892 1270316 77763608 0 0 0 368 108699 414696 20 37 42 0 0
18 0 5841744 9247004 1270316 77763616 0 0 0 576 112248 419663 20 37 42 1 0
24 0 5841744 9248700 1270316 77763624 0 0 0 696 112086 416726 20 36 43 1 0
20 0 5841744 9246564 1270316 77763632 0 0 0 236 114607 414511 20 37 42 0 0
27 0 5841744 9244172 1270316 77763632 0 0 0 608 112999 414641 20 38 41 0 0
33 0 5841744 9247596 1270316 77763608 0 0 0 296 102071 421014 21 36 43 0 0
16 1 5841744 9243064 1270316 77763664 0 0 0 240 104041 424074 21 37 41 0 0
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----

我们可以明显的观察到:

  1. 当前 cs、in 此时剧增。
  2. sy+us 的 CPU 占用超过 90%。
  3. r 就绪队列长度达到 16 个超过了 CPU 核心数 8 个。(槽,没压出来)

pidstat -w -u -t 1

-w表示查看进程切换信息,-u查看CPU信息,-t查看线程切换信息

09:50:00 PM UID TGID TID %usr %system %guest %CPU CPU Command
09:50:01 PM 1100 18082 - 103.96 1133.66 0.00 1237.62 22 sysbench
09:50:01 PM 1100 - 18082 0.00 0.00 0.00 0.00 22 |__sysbench
09:50:01 PM 1100 - 18083 0.00 7.92 0.00 7.92 8 |__sysbench
09:50:01 PM 1100 - 18084 0.99 6.93 0.00 7.92 0 |__sysbench
09:50:01 PM 1100 - 18085 0.00 6.93 0.00 6.93 3 |__sysbench
09:50:01 PM 1100 - 18086 0.00 7.92 0.00 7.92 3 |__sysbench
09:50:01 PM 1100 - 18087 1.98 5.94 0.00 7.92 24 |__sysbench
09:50:01 PM 1100 - 18088 0.99 6.93 0.00 7.92 22 |__sysbench
09:50:01 PM 1100 - 18089 0.99 5.94 0.00 6.93 22 |__sysbench
09:50:01 PM 1100 - 18090 0.00 6.93 0.00 6.93 24 |__sysbench
09:50:01 PM 1100 - 18091 0.99 7.92 0.00 8.91 6 |__sysbench
09:50:01 PM 1100 - 18092 0.00 6.93 0.00 6.93 28 |__sysbench
09:50:01 PM 1100 - 18093 0.00 5.94 0.00 5.94 20 |__sysbench
09:50:01 PM 1100 - 18094 1.98 7.92 0.00 9.90 28 |__sysbench
09:50:01 PM 1100 - 18095 0.99 6.93 0.00 7.92 10 |__sysbench
09:50:01 PM 1100 - 18096 0.00 7.92 0.00 7.92 8 |__sysbench
09:50:01 PM 1100 - 18097 0.99 6.93 0.00 7.92 5 |__sysbench
09:50:01 PM 1100 - 18098 0.00 6.93 0.00 6.93 5 |__sysbench

所以我们可以看到大量的sysbench线程存在很多的上下文切换。

分析 in 中断问题

我们可以查看系统的

watch -d cat /proc/softirqs

以及

watch -d cat /proc/interrupts

来查看系统的软中断和硬中断(内核中断)。我们这里主要观察/proc/interrupts即可。

妈的超大一屏幕,没看出来个啥

截个图给你们感受下

 

总结

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

CPU 使用率

除了系统负载、上下文切换信息,最直观的 CPU 问题指标就是 CPU 使用率信息。Linux 通过/proc虚拟文件系统向用户控件提供系统内部状态信息,其中/proc/stat则是 CPU 和任务信息统计。

cat /proc/stat | grep cpu

cpu 6418667257 199753 985546439 87112509362 1920168846 62531 58318839 0 0 0
cpu0 319772892 13710 40795064 2461401254 159650806 3344 5910924 0 0 0
cpu1 376250284 3180 22011610 2592022162 11228471 0 1583674 0 0 0
cpu2 319255186 18818 35539586 2443427110 194918493 4498 4141439 0 0 0
cpu3 311570832 1982 22095008 2659753043 11443160 0 390556 0 0 0
cpu4 351375940 21602 31598891 2406544155 205344918 4239 4163049 0 0 0
cpu5 297258592 3969 23007094 2673150140 11765090 0 279483 0 0 0
cpu6 355218370 18570 30702383 2402252543 207501579 4439 3757052 0 0 0
cpu7 286461468 4919 23565105 2683028699 11789607 0 275728 0 0 0
cpu8 350298387 23049 29054584 2393395803 227563599 2928 2373213 0 0 0
cpu9 274339523 3265 23303336 2695204965 11844589 0 273762 0 0 0
cpu10 348852381 20653 29946042 2418168228 198474721 4535 3767787 0 0 0
cpu11 260986676 2852 23105246 2708653796 11820796 0 274532 0 0 0
cpu12 334521677 16846 29260685 2464848813 166265426 4499 3770851 0 0 0
cpu13 246909254 2387 22846593 2722862334 11865884 0 277386 0 0 0
cpu14 316523370 17705 30586093 2486842358 160244701 4679 3802016 0 0 0
cpu15 227676688 2093 23024742 2741646184 11854428 0 282848 0 0 0
cpu16 82447561 1755 24276456 2877783762 36988581 4147 2688940 0 0 0
cpu17 71529953 280 15597450 2944617729 2705462 0 73473 0 0 0
cpu18 133215807 5768 79349864 2782324805 32397545 3492 3359664 0 0 0
cpu19 124874164 3519 64352456 2847083546 2896017 0 241954 0 0 0
cpu20 121238536 2164 64502885 2800808681 33963848 3507 3354872 0 0 0
cpu21 137638748 622 65075129 2827786422 2544974 0 248916 0 0 0
cpu22 76208246 1024 27995668 2882397156 35430771 3608 2553942 0 0 0
cpu23 88456403 501 25887767 2916969352 2713769 0 113887 0 0 0
cpu24 71460693 1428 24612612 2889603906 36070452 3682 2553191 0 0 0
cpu25 80665646 713 21162523 2929241589 2824128 0 95640 0 0 0
cpu26 69917552 1190 24158632 2892533340 35604504 3482 2436233 0 0 0
cpu27 78145890 530 19648413 2932932278 2906918 0 89054 0 0 0
cpu28 71331930 919 24488613 2892561160 34539903 3604 2405811 0 0 0
cpu29 77351778 605 18715650 2934078215 3128529 0 86096 0 0 0
cpu30 71687663 2734 24876870 2888128801 36353649 3842 2534758 0 0 0
cpu31 85225151 388 20403378 2920457016 5523516 0 158098 0 0 0

这里每一列的含义如下:

  1. user(通常缩写为 us),代表用户态 CPU 时间。注意,它不包括下面的 nice 时间,但包括了 guest 时间。
  2. nice(通常缩写为 ni),代表低优先级用户态 CPU 时间,也就是进程的 nice 值被调整为 1-19 之间时的 CPU 时间。这里注意,nice 可取值范围是 -20 到 19,数值越大,优先级反而越低。
  3. system(通常缩写为 sys),代表内核态 CPU 时间。
  4. idle(通常缩写为 id),代表空闲时间。注意,它不包括等待 I/O 的时间(iowait)。
  5. iowait(通常缩写为 wa),代表等待 I/O 的 CPU 时间。
  6. irq(通常缩写为 hi),代表处理硬中断的 CPU 时间。
  7. softirq(通常缩写为 si),代表处理软中断的 CPU 时间。
  8. steal(通常缩写为 st),代表当系统运行在虚拟机中的时候,被其他虚拟机占用的 CPU 时间。
  9. guest(通常缩写为 guest),代表通过虚拟化运行其他操作系统的时间,也就是运行虚拟机的 CPU 时间。
  10. guest_nice(通常缩写为 gnice),代表以低优先级运行虚拟机的时间。

这里我们可以使用toppspidstat等工具方便的查询这些数据,可以很方便的看到 CPU 使用率很高的进程,这里我们可以通过这些工具初步定为,但是具体的问题原因还需要其他方法继续查找。

这里我们可以使用perf top方便查看热点数据,也可以使用perf record可以将当前数据保存起来方便后续使用perf report查看。

这里总结一下 CPU 使用率问题及排查思路:

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

CPU 问题排查套路

CPU 使用率主要包含以下几个方面:

  1. 用户 CPU 使用率,包括用户态 CPU 使用率(user)和低优先级用户态 CPU 使用率(nice),表示 CPU 在用户态运行的时间百分比。用户 CPU 使用率高,通常说明有应用程序比较繁忙。
  2. 系统 CPU 使用率,表示 CPU 在内核态运行的时间百分比(不包括中断)。系统 CPU 使用率高,说明内核比较繁忙。
  3. 等待 I/O 的 CPU 使用率,通常也称为 iowait,表示等待 I/O 的时间百分比。iowait 高,通常说明系统与硬件设备的 I/O 交互时间比较长。
  4. 软中断和硬中断的 CPU 使用率,分别表示内核调用软中断处理程序、硬中断处理程序的时间百分比。它们的使用率高,通常说明系统发生了大量的中断。
  5. 除在虚拟化环境中会用到的窃取 CPU 使用率(steal)和客户 CPU 使用率(guest),分别表示被其他虚拟机占用的 CPU 时间百分比,和运行客户虚拟机的 CPU 时间百分比。

平均负载

反应了系统的整体负载情况,可以查看过去 1 分钟、过去 5 分钟和过去 15 分钟的平均负载。

上下文切换

上下文切换主要关注 2 项指标:

  1. 无法获取资源而导致的自愿上下文切换。
  2. 被系统强制调度导致的非自愿上下文切换。

CPU 缓存命中率

CPU 的访问速度远大于内存访问,这样在 CPU 访问内存时不可避免的要等待内存响应。为了协调 2 者的速度差距出现了 CPU 缓存(多级缓存)。如果 CPU 缓存命中率越高则性能会更好,我们可以使用以下工具查看 CPU 缓存命中率,工具地址、项目地址 perf-tools

# ./cachestat -tCounting cache functions... Output every 1 seconds.TIME         HITS   MISSES  DIRTIES    RATIO   BUFFERS_MB   CACHE_MB08:28:57      415        0        0   100.0%            1        19108:28:58      411        0        0   100.0%            1        19108:28:59      362       97        0    78.9%            0          808:29:00      411        0        0   100.0%            0          908:29:01      775    20489        0     3.6%            0         8908:29:02      411        0        0   100.0%            0         8908:29:03     6069        0        0   100.0%            0         8908:29:04    15249        0        0   100.0%            0         8908:29:05      411        0        0   100.0%            0         8908:29:06      411        0        0   100.0%            0         8908:29:07      411        0        3   100.0%            0         89[...]

总结

通过性能指标查工具(CPU 相关)

性能指标 工具 说明
平均负载 uptime
top
uptime 简单展示最近一段时间的平均负载
top 展示更多指标
CPU 使用率 vmstat
mpstat
top
sar
/proc/stat
top、vmstat、mpstat 只可以动态查看当前,而 sar 可以查看历史
/proc/stat 是其他性能工具的数据来源
进程 CPU 使用率 top
pidstat
ps
htop
atop
top、ps 可以以排序方式展示进程 CPU、pidstat 不可排序展示
htop、atop 则以不同颜色展示各类数据更直观
系统上下文切换 vmstat 展示上下文切换此时、运行状态、不可中断状态进程数量
进程上下文切换 pidstat 展示项很多,包括进程上下文切换信息
软中断 top
/proc/softirqs
mpstat
top 可查看软中断 CPU 使用率
/proc/softirqs 和 mpstat 则可以查看每个 CPU 上的累计信息
硬中断 vmstat
/proc/interrupts
vmstat 查看总中断次数信息
/proc/interrupts 查看各种中断在每个 CPU 核心上的累计信息
网络 dstat
sar
tcpdump
dstat、sar 较详细的展示出总的网络收发情况
tcpdump 提供动态抓取数据包的能力
IO dstat、sar 2 者都提供了详细的 IO 整体情况
CPU 信息 /proc/cpuinfo
lscpu
都可以查看 CPU 信息
系统分析 perf
execsnoop
perf 分析各种内核函数调用、热点函数信息
execsnoop 监控短时进程

根据工具查性能指标(CPU 相关)

性能工具 CPU 性能指标
uptime 5、10、15 分钟内的平均负载展示
top 平均负载、运行队列、CPU 各项使用率、进程状态和 CPU 使用率
htop top 增强版,以不同颜色区分不同类型进程,展示更直观
atop CPU、内存、磁盘、网络资源全访问监控,十分齐全
vmstat 系统整体 CPU 使用率、上下文切换次数、中断次数,还包括处于运行(r)和不可中断状态(b)的进程数量
pidstat 进程、线程(-t)的每个 CPU 占用信息,中断上下文切换次数
/proc/softirqs 展示每个 CPU 上的软中断类型及次数
/proc/inerrupts 展示每个 CPU 上的硬中断类型及次数
ps 每个进程的状态和 CPU 使用率
pstree 进程的父子关系展示
dstat 系统整体 CPU 使用率(以及相关 IO、网络信息)
sar 系统整体 CPU 使用率,以及使用率历史信息
strace 跟踪进程的系统调用
perf CPU 性能事件分析,例如:函数调用链、CPU 缓存命中率、CPU 调度等
execsnoop 短时进程分析

CPU 问题排查方向

有了以上性能工具,在实际遇到问题时我们并不可能全部性能工具跑一遍,这样效率也太低了,所以这里可以先运行几个常用的工具 top、vmstat、pidstat 分析系统大概的运行情况然后在具体定位原因。

top 系统CPU => vmstat 上下文切换次数 => pidstat 非自愿上下文切换次数 => 各类进程分析工具(perf strace ps execsnoop pstack)
top 用户CPU => pidstat 用户CPU => 一般是CPU计算型任务
top 僵尸进程 =>  各类进程分析工具(perf strace ps execsnoop pstack)
top 平均负载 => vmstat 运行状态进程数 =>  pidstat 用户CPU => 各类进程分析工具(perf strace ps execsnoop pstack)
top 等待IO CPU => vmstat 不可中断状态进程数  => IO分析工具(dstat、sar -d)
top 硬中断 => vmstat 中断次数 => 查看具体中断类型(/proc/interrupts)
top 软中断 => 查看具体中断类型(/proc/softirqs) => 网络分析工具(sar -n、tcpdump) 或者 SCHED(pidstat 非自愿上下文切换)

CPU 问题优化方向

性能优化往往是多方面的,CPU、内存、网络等都是有关联的,这里暂且给出 CPU 优化的思路,以供参考。

程序优化

  1. 基本优化:程序逻辑的优化比如减少循环次数、减少内存分配,减少递归等等。
  2. 编译器优化:开启编译器优化选项例如gcc -O2对程序代码优化。
  3. 算法优化:降低苏研发复杂度,例如使用nlogn的排序算法,使用logn的查找算法等。
  4. 异步处理:例如把轮询改为通知方式
  5. 多线程代替多进程:某些场景下多线程可以代替多进程,因为上下文切换成本较低
  6. 缓存:包括多级缓存的使用(略)加快数据访问

系统优化

  1. CPU 绑定:绑定到一个或多个 CPU 上,可以提高 CPU 缓存命中率,减少跨 CPU 调度带来的上下文切换问题
  2. CPU 独占:跟 CPU 绑定类似,进一步将 CPU 分组,并通过 CPU 亲和性机制为其分配进程。
  3. 优先级调整:使用 nice 调整进程的优先级,适当降低非核心应用的优先级,增高核心应用的优先级,可以确保核心应用得到优先处理。
  4. 为进程设置资源限制:使用 Linux cgroups 来设置进程的 CPU 使用上限,可以防止由于某个应用自身的问题,而耗尽系统资源。
  5. NUMA 优化:支持 NUMA 的处理器会被划分为多个 Node,每个 Node 有本地的内存空间,这样 CPU 可以直接访问本地空间内存。
  6. 中断负载均衡:无论是软中断还是硬中断,它们的中断处理程序都可能会耗费大量的 CPU。开启 irqbalance 服务或者配置 smp_affinity,就可以把中断处理过程自动负载均衡到多个 CPU 上。

 

sysbench安装:https://github.com/akopytov/sysbench#debianubuntu

CPU参数模拟:https://mp.weixin.qq.com/s/7HGjAy_R_sdpfckFlFr0cw

load average参数:https://www.cnblogs.com/kaituorensheng/p/3602805.html

你可能感兴趣的:(jvm,工具窍门)