在之前CPU负载的几种情况相关文章中,我们描述了几种情况导致CPU负载高。
最神奇的就是当多个活跃进程(多于CPU个数)在执行操作时,通过vmstat命令可以看到对应的cs(context switch)很高,并同时引起了CPU的高负载。
那么为什么CPU上下文切换会引起高负载均衡呢?我们一起来学习下
1.什么是CPU上下文切换?我们知道,现代CPU基本都是基于多核、基于抢占式。
CPU会给每个任务一定的时间分片来执行任务,当A进程时间分片使用完成之后,就会切换到下一个B进程来执行,这样使得多个进程在同一个CPU上执行成为可能。
2.引起上下文切换的场景* 当前任务时间分片使用完成之后,CPU调度下一个任务;
* 当前任务被IO阻塞,CPU调度则挂起当前任务,执行下一个任务;
* 当前任务抢占锁资源失败,CPU调度挂起当前任务,执行下一个任务;
* 用户主动挂起当前任务;
* 硬件中断;
3.上下文切换为什么耗CPU?简单来说,CPU要想切换一个进程执行,就需要将当前正在执行的进程任务所对应的上下文资源保存下来,等待后续CPU调度(如果不保存,等下次CPU再次调度该任务时,就不知道从哪里开始执行了)。
这些上下文资源包括:用户空间数据(虚拟内存、栈、全局变量)和内核空间数据(内核堆栈、寄存器)
所以当CPU频繁的把工作都浪费在这些上下文资源的保存、加载上,那么真正投入到任务执行中的时间就少很多了。
4.CPU上下文切换数多少算正常?实际这个还真不好说,我们可以在机器比较空闲的时候通过vmstat命令来测试以下看看。以下是笔者的docker机器空闲情况下的切换情况
root@7bc18553126f:/# vmstat -w 3
procs -----------------------memory---------------------- ---swap-- -----io---- -system-- --------cpu--------
r b swpd free buff cache si so bi bo in cs us sy id wa st
2 0 118168 95464 128584 1540208 0 0 23 32 105 42 3 0 96 0 0
0 0 118168 94960 128584 1540208 0 0 0 0 249 357 0 0 100 0 0
0 0 118168 94992 128584 1540208 0 0 0 0 213 354 0 0 100 0 0
看system这一列,in(interrupt)中断就200+,cs(context switch)上下文切换就300+的水平。
这个在笔者这里算是正常的水平。
5.模拟多线程切换我们通过sysbench命令来模拟多个线程(多于CPU核数)切换的问题。
来看下当多线程切换时的cs/in相较于正常情况下有多大差距
5.1 sysbench模拟切换执行以下命令,启动10个线程,执行5分钟后结束
root@7bc18553126f:/# sysbench --threads=10 --max-time=300 threads run
WARNING: --max-time is deprecated, use --time instead
sysbench 1.0.11 (using system LuaJIT 2.1.0-beta3)
Running the test with following options:
Number of threads: 10
Initializing random number generator from current time
Initializing worker threads...
Threads started!
5.2 vmstat查看具体信息
root@7bc18553126f:/# vmstat -w 3
procs -----------------------memory---------------------- ---swap-- -----io---- -system-- --------cpu--------
r b swpd free buff cache si so bi bo in cs us sy id wa st
8 0 118168 103756 129456 1527740 0 0 23 32 105 72 3 0 96 0 0
7 0 118168 103756 129456 1527740 0 0 0 0 25569 1485097 19 68 13 0 0
7 0 118168 103504 129456 1527724 0 0 0 0 25260 1472618 18 68 14 0 0
7 0 118168 103504 129456 1527724 0 0 0 0 25318 1480719 18 68 13 0 0
直接关注system in/cs这两列,上面空闲时的CPU切换和中断也就200 300+的样子,现在一下子飙升到100W+,说明上下文切换很疯狂
5.3 pidstat查看具体切换的进程老规矩,我们使用 pidstat -wu的方式同时查看进程系统资源使用和切换相关数据
root@7bc18553126f:/# pidstat -wu 3
Linux 5.10.76-linuxkit (7bc18553126f) 03/13/22 _aarch64_ (4 CPU)
10:35:19 UID PID %usr %system %guest %wait %CPU CPU Command
10:35:22 0 54333 0.33 0.00 0.00 0.00 0.33 1 watch
10:35:22 0 79233 80.67 100.00 0.00 0.00 100.00 2 sysbench
10:35:19 UID PID cswch/s nvcswch/s Command
10:35:22 0 54333 1.00 2.00 watch
10:35:22 0 79426 0.33 0.00 pidstat
可以看到 PID=79233的进程CPU使用率已经100%了,实际应该是已经超过100了,system使用就已经是100了。
但是没有看到sysbench相关切换数据。
由于sysbench工具创建了多个线程来执行任务,所以在使用pidstat命令时,我们需要再加上-t来展示下线程相关信息
root@7bc18553126f:/# pidstat -wut 3
Linux 5.10.76-linuxkit (7bc18553126f) 03/13/22 _aarch64_ (4 CPU)
10:34:32 UID TGID TID %usr %system %guest %wait %CPU CPU Command
10:34:35 0 79233 - 77.33 100.00 0.00 0.00 100.00 2 sysbench
10:34:35 0 - 79234 8.00 30.67 0.00 22.33 38.67 0 |__sysbench
10:34:35 0 - 79235 7.33 31.00 0.00 21.33 38.33 2 |__sysbench
10:34:35 0 - 79236 7.00 30.33 0.00 22.00 37.33 0 |__sysbench
10:34:35 0 - 79237 7.33 31.67 0.00 22.00 39.00 1 |__sysbench
10:34:35 0 - 79238 7.67 29.67 0.00 22.00 37.33 3 |__sysbench
10:34:35 0 - 79239 8.33 30.33 0.00 23.00 38.67 3 |__sysbench
10:34:35 0 - 79240 7.67 30.33 0.00 22.00 38.00 3 |__sysbench
10:34:35 0 - 79241 8.33 29.33 0.00 22.00 37.67 2 |__sysbench
10:34:35 0 - 79242 7.67 30.33 0.00 22.67 38.00 3 |__sysbench
10:34:35 0 - 79243 8.33 29.00 0.00 22.33 37.33 0 |__sysbench
10:34:32 UID TGID TID cswch/s nvcswch/s Command
10:34:35 0 54333 - 1.00 1.33 watch
10:34:35 0 - 54333 1.00 1.33 |__watch
10:34:35 0 - 79234 23777.00 107584.67 |__sysbench
10:34:35 0 - 79235 25307.67 104601.33 |__sysbench
10:34:35 0 - 79236 25521.00 103425.00 |__sysbench
10:34:35 0 - 79237 25244.67 109579.00 |__sysbench
10:34:35 0 - 79238 23200.33 107219.67 |__sysbench
10:34:35 0 - 79239 24584.33 115980.33 |__sysbench
10:34:35 0 - 79240 23894.00 107087.33 |__sysbench
10:34:35 0 - 79241 25771.33 108859.67 |__sysbench
10:34:35 0 - 79242 22596.00 114085.00 |__sysbench
10:34:35 0 - 79243 24455.00 107223.33 |__sysbench
10:34:35 0 79356 - 0.33 0.33 pidstat
10:34:35 0 - 79356 0.33 0.33 |__pidstat
通过线程这个视角就很明显了,可以看到sysbench创建出来的多个线程,cswch/s nvcswch/s都很高,被动切换更高。
总结:通过pidstat -wut 3命令,可以查看到进程和里面的线程CPU使用、上下文切换相关数据。
主动切换(cswch/s)多,说明大家都在等资源,这时候资源本身是瓶颈;
被动切换(nvcswch/s)多,说明大家都在被强制调度,都在争抢CPU资源,此时CPU变成了瓶颈;
参考:极客时间