CPU上下文切换是保证 Linux系统正常工作的一个核心功能,按照不同场景,可以分为进程上下文切换、线程上下文切换和中断上下文切换。究竟怎么分析CPU上下文切换的问题。
过多的上下文切换,会把CPU时间消耗在寄存器、内核栈以及虚拟内存等数据的保存和恢复上,缩短进程真正运行的时间,成了系统性能大幅下降的一个元凶。
既然上下文切换对系统性能影响那么大,到底要怎么査看上下文切换呢?可以使用vmstat这个工具,来查询系统的上下文切换情况。
vmstat是常用的系统性能分析工具,主要用来分析系统的内存使用情况,也常用来分析 CPU上下文切换和中断的次数。
[root@www ~]# vmstat 2 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 0 391648 2076 286040 0 0 69 52 70 66 1 1 99 0 0 0 0 0 391656 2076 286040 0 0 0 0 49 42 0 0 100 0 0 0 0 0 391656 2076 286040 0 0 0 0 44 38 0 0 100 0 0
procs(进程)
r:当前运行队列中线程的数目,代表线程处于可运行状态,但CPU还未能执行,这个值可以作为判断CPU是否繁忙的一个指标;当这个值超过了CPU数目,就会出现CPU瓶颈了;这个我们可以结合top命令的负载值同步评估系统性能(等待运行的进程数((Running or Runnable)是就绪队列的长度,也就是正在运行和等待CPU的进程数))
b:处在非中断睡眠状态的进程数
system(系统)这2个值越大,会看到由内核消耗的CPU时间会越大
in:(interrupt)则是每秒中断的次数,包括时钟中断
cs: (context switch)是每秒上下文切换的次数
cpu(以百分比表示)
us:用户进程执行时间(user time);
sy:系统进程执行时间(system time);
id:空闲时间(包括IO等待时间);
wa:等待IO时间;wa的值高时,说明IO等待比较严重,这可能由于磁盘大量作随机访问造成,也有可能磁盘出现瓶颈。
r: 表示运行队列(就是说多少个进程真的分配到CPU),我测试的服务器目前CPU比较空闲,没什么程序在跑,当这个值超过了CPU数目,就会出现CPU瓶颈了。这个也和top的负载有关系,一般负载超过了3就比较高,超过了5就高,超过了10就不正常了,服务器的状态很危险。top的负载类似每秒的运行队列。如果运行队列过大,表示你的CPU很繁忙,一般会造成CPU使用率很高。
cs:每秒上下文切换次数,例如我们调用系统函数,就要进行上下文切换,线程的切换,也要进程上下文切换,这个值要越小越好,太大了,要考虑调低线程或者进程的数目,例如在apache和nginx这种web服务器中,我们一般做性能测试时会进行几千并发甚至几万并发的测试,选择web服务器的进程可以由进程或者线程的峰值一直下调,压测,直到cs到一个比较小的值,这个进程和线程数就是比较合适的值了。系统调用也是,每次调用系统函数,我们的代码就会进入内核空间,导致上下文切换,这个是很耗资源,也要尽量避免频繁调用系统函数。上下文切换次数过多表示你的CPU大部分浪费在上下文切换,导致CPU干正经事的时间少了,CPU没有充分利用,是不可取的。
vmstat只给出了系统总体的上下文切换情况,要想查看每个进程的详细情况,就需要使用pidstat 了。给它加上-w选项,你就可以查看每个进程上下文切换的情况了。
[root@www ~]# pidstat -w 5 Linux 3.10.0-693.el7.x86_64 (www.lutixia.com) 07/02/2020 _x86_64_ (2 CPU) 08:17:53 PM UID PID cswch/s nvcswch/s Command 08:17:58 PM 0 3 0.40 0.00 ksoftirqd/0 08:17:58 PM 0 7 0.40 0.00 migration/0 08:17:58 PM 0 9 1.20 0.00 rcu_sched 08:17:58 PM 0 10 0.20 0.00 watchdog/0 08:17:58 PM 0 11 0.20 0.00 watchdog/1 08:17:58 PM 0 12 0.20 0.00 migration/1 ————————————————
这个结果中有两列内容是我们的重点关注对象。
一个是cswch,表示每秒自愿上下文切换 (voluntary context switches)的次数,另一个则是nvcswch ,表示每秒非自愿上下文切换 (non voluntary context switches)的次数
所谓自愿上下文切换,是指进程无法获取所需资源,导致的上下文切换。比如说,I/O、内存等系统资源不足时,就会发生自愿上下文切换。
而非自愿上下文切换,则是指进程由于时间片巳到等原因,被系统强制调度,进而发生的上下文切换。比如说,大量进程都在争抢CPU时,就容易发生非自愿上下文切换。
这两列如果数值比较大意味着不同的性能问题:
自愿上下文切换时说明进程在等待资源,有可能发生了I/O等问题
非自愿上下文切换,说明进程在被强制调度,也就是在争抢CPU
中断次数多了,说明CPU在被中断处理程序占用。可以通过/proc/interrupts 查看
————————————————
环境准备
使用sysbench来模拟系统多线程调度切换的情况。
sysbench是一个多线程的基准测试工具,一般用来评估不同系统参数下的MySQL数据库库负载情况。这次案例中,我们只把它当成异常进程来看,作用是模拟上下文切换过多的问题。
下面的案例基于Centos 7.X,当然,其他的Linux系统同样适用。环境如下所示:
•机器配置:2 CPU, 1GB内存
•预先安装 sysbench 和 sysstat包,如 yum install epel* sysbench sysstat -y
操作开始前,你需要打开三个终端,登录到同一台Linux,并安装好上面两个软件包。安装完成后,你可以先用vmstat看一下空闲系统的上下文切次数:
root@ubuntu:~# vmstat 1 procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 1 0 0 165232256 5355296 87115856 0 0 0 4 0 0 0 0 100 0 0 0 0 0 165234240 5355296 87115872 0 0 0 100 6265 10781 0 1 99 0 0 0 0 0 165233760 5355296 87115872 0 0 0 0 3884 7068 0 0 100 0 0 0 0 0 165233760 5355296 87115880 0 0 0 84 6804 11679 0 0 99 0 0 0 0 0 165233760 5355296 87115880 0 0 0 0 2998 5518 0 0 100 0 0 0 0 0 165234016 5355296 87115888 0 0 0 36 4539 8432 0 0 100 0 0 ^C root@ubuntu:~#
root@ubuntu:~# vmstat 2 1 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 165234288 5355296 87116608 0 0 0 4 0 0 0 0 100 0 0 root@ubuntu:~#
可以看到上下文切换次数是cs 0,中断次数是25,r和b都是0因为系统比较空闲,没有运行比较繁忙的任务。
首先,在第一个终端里运行sysbench ,模拟系统多线程调度的瓶颈:
root@ubuntu:~# 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!
root@ubuntu:~# ps -elf | grep sysbench 0 S root 22663 22322 99 80 0 - 27397 futex_ 17:34 pts/3 00:03:41 sysbench --threads=10 --max-time=300 threads run 0 S root 22776 22728 0 80 0 - 1096 pipe_w 17:34 pts/2 00:00:00 grep sysbench root@ubuntu:~#
root@ubuntu:~# ps -ef | grep 22663 root 22663 22322 99 17:34 pts/3 00:11:48 sysbench --threads=10 --max-time=300 threads run root 23028 22728 0 17:35 pts/2 00:00:00 grep 22663 root@ubuntu:~# ps -T -p 22663 PID SPID TTY TIME CMD 22663 22663 pts/3 00:00:00 sysbench 22663 22664 pts/3 00:02:03 sysbench 22663 22665 pts/3 00:02:04 sysbench 22663 22666 pts/3 00:02:03 sysbench 22663 22667 pts/3 00:02:03 sysbench 22663 22668 pts/3 00:02:03 sysbench 22663 22669 pts/3 00:02:03 sysbench 22663 22670 pts/3 00:02:03 sysbench 22663 22671 pts/3 00:02:03 sysbench 22663 22672 pts/3 00:02:03 sysbench 22663 22673 pts/3 00:02:03 sysbench root@ubuntu:~#
vmstat系统层面定位问题
接着,在第二个终端运行vmstat,观察上下文切换情况:
root@ubuntu:~# vmstat 1 procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 9 0 0 165236416 5355296 87121232 0 0 0 4 0 0 0 0 100 0 0 10 0 0 165236480 5355296 87121232 0 0 0 100 173173 340707 3 11 86 0 0 9 0 0 165236800 5355296 87121248 0 0 0 0 172025 338301 3 11 86 0 0 9 0 0 165236864 5355296 87121256 0 0 0 80 164349 322752 3 11 86 0 0 10 0 0 165236928 5355296 87121256 0 0 0 24 161035 316385 3 11 86 0 0 9 0 0 165236912 5355296 87121264 0 0 0 76 162196 318611 3 11 86 0 0 9 0 0 165236912 5355296 87121264 0 0 0 2104 168417 330620 3 11 86 0 0 ^C root@ubuntu:~#
[root@www ~]# vmstat 1 procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 9 0 0 381900 2076 293176 0 0 29 23 240 3698 0 2 98 0 0 7 0 0 381892 2076 293176 0 0 0 0 23350 1354895 7 91 3 0 0 8 0 0 381892 2076 293176 0 0 0 0 25311 1337914 7 91 2 0 0 6 0 0 381892 2076 293176 0 0 0 0 25632 1440565 8 91 2 0 0
你应该可以发现,CS列的上下文切换次数从之前的46骤然上升到了 130W+。同时,注意观察 其他几个指标:
• r列:就绪队列的长度已经到了 6+,远远超过了系统CPU的个数 2,所以肯定会有大量的 CPU竞争
• us (user)和sy (system)列:这两列的CPU使用率加起来上升到了100%(91+7 91+8 98+2),其中系统 CPU使用率,也就是sy列高达91%,说明CPU主要是被内核占用了
• in列中断次数也上升到了 2W+左右,说明中断处理也是个潜在的问题
综合这几个指标,我们可以知道,系统的就绪队列过长,也就是正在运行和等待CPU的进程数量过多,导致了大量的上下文切换,而上下文切换又导致了系统CPU的占用率升高。 14/article/details/107094209
pidstat具体定位vmstat产生的问题,缩小范围定位问题
那么到底是什么进程导致了这些问题呢?第三个终端再用pidstat来看一下,CPU和进程上下文切换的情况
root@ubuntu:~# pidstat -w -u 1 Linux 5.0.0-23-generic (ubuntu) Tuesday, March 16, 2021 _aarch64_ (64 CPU) 05:40:06 HKT UID PID %usr %system %guest %wait %CPU CPU Command 05:40:07 HKT 0 11 0.00 0.95 0.00 0.00 0.95 12 rcu_sched 05:40:07 HKT 0 1078 0.95 0.00 0.00 0.00 0.95 15 systemd-journal 05:40:07 HKT 0 3361 0.00 0.95 0.00 0.00 0.95 29 qemu-system-aar 05:40:07 HKT 0 9466 0.00 0.95 0.00 0.00 0.95 26 kube-controller 05:40:07 HKT 0 12405 0.00 0.95 0.00 0.00 0.95 28 etcd 05:40:07 HKT 0 12424 0.00 0.95 0.00 0.00 0.95 36 kube-apiserver 05:40:07 HKT 0 12848 0.95 0.00 0.00 0.00 0.95 28 kubelet 05:40:07 HKT 0 24247 1.90 3.81 0.00 0.00 5.71 41 pidstat 05:40:07 HKT 0 34081 0.95 0.00 0.00 0.00 0.95 55 containerd-shim 05:40:07 HKT 0 34127 0.00 0.95 0.00 0.00 0.95 30 containerd-shim
[root@www ~]# uptime 22:08:21 up 2:05, 3 users, load average: 5.97, 2.90, 2.00 #-w表示进程切换指标,-u表示CPU使用率 [root@www ~]# pidstat -w -u 1 Linux 3.10.0-693.el7.x86_64 (www.lutixia.com) 07/02/2020 _x86_64_ (2 CPU) 08:54:57 PM UID PID %usr %system %guest %CPU CPU Command 08:54:58 PM 0 689 0.00 0.96 0.00 0.96 1 vmtoolsd 08:54:58 PM 0 1259 12.50 100.00 0.00 100.00 1 sysbench 08:54:58 PM 0 1272 0.00 0.96 0.00 0.96 0 pidstat 08:54:57 PM UID PID cswch/s nvcswch/s Command 08:54:58 PM 0 3 1.92 0.00 ksoftirqd/0 08:54:58 PM 0 9 17.31 0.00 rcu_sched 08:54:58 PM 0 25 0.96 0.00 kworker/0:1 08:54:58 PM 0 252 0.96 0.00 kworker/u256:2 08:54:58 PM 0 689 10.58 0.00 vmtoolsd 08:54:58 PM 0 1068 0.96 0.00 kworker/0:1H 08:54:58 PM 0 1213 1.92 0.00 kworker/1:2
从pidstat的输出你可以发现,CPU使用率的升高果然是sysbench导致的,它的CPU使用率已经达到了100%。但上下文切换则是来自其他进程,包括非自愿上下文切换频率最高的 pidstat,以及自愿上下文切换频率最高的内核线程kworker。
pidstat输出的上下文切换次数,加起来也就几百,比vmstat的130W+明显小了太多。这是怎么回事呢?难道是工具本身出了错吗?
Linux调度的基本单位实际上是线程,而我们的场景sysbench模拟的也是线程的调度问题,pidstat忽略了线程的数据,pidstat默认显示进程的指标数据,加上-t参数后,才会输出线程的指标。
[root@www ~]# pidstat -wt 1 Linux 3.10.0-693.el7.x86_64 (www.lutixia.com) 07/02/2020 _x86_64_ (2 CPU) 09:18:38 PM UID TGID TID cswch/s nvcswch/s Command 09:18:39 PM 0 9 - 3.96 0.00 rcu_sched 09:18:39 PM 0 - 9 3.96 0.00 |__rcu_sched 09:18:39 PM 0 13 - 1.98 0.00 ksoftirqd/1 09:18:39 PM 0 - 13 1.98 0.00 |__ksoftirqd/1 09:18:39 PM 0 25 - 2.97 0.00 kworker/0:1 09:18:39 PM 0 - 25 2.97 0.00 |__kworker/0:1 09:18:39 PM 0 32 - 0.99 0.00 khugepaged 09:18:39 PM 0 - 32 0.99 0.00 |__khugepaged 09:18:39 PM 0 252 - 0.99 0.00 kworker/u256:2 09:18:39 PM 0 - 252 0.99 0.00 |__kworker/u256:2 09:18:39 PM 0 - 706 0.99 0.00 |__in:imjournal 09:18:39 PM 0 689 - 9.90 0.00 vmtoolsd 09:18:39 PM 0 - 689 9.90 0.00 |__vmtoolsd 09:18:39 PM 0 - 1011 0.99 0.00 |__tuned 09:18:39 PM 0 1341 - 1.98 0.00 kworker/1:2 09:18:39 PM 0 - 1341 1.98 0.00 |__kworker/1:2 09:18:39 PM 0 - 1343 20120.79 122291.09 |__sysbench 09:18:39 PM 0 - 1344 13162.38 110521.78 |__sysbench 09:18:39 PM 0 - 1345 26090.10 119710.89 |__sysbench 09:18:39 PM 0 - 1346 23462.38 96952.48 |__sysbench 09:18:39 PM 0 - 1347 16571.29 107426.73 |__sysbench 09:18:39 PM 0 - 1348 22124.75 116013.86 |__sysbench 09:18:39 PM 0 - 1349 20953.47 114319.80 |__sysbench 09:18:39 PM 0 - 1350 21472.28 108875.25 |__sysbench 09:18:39 PM 0 - 1351 17744.55 120934.65 |__sysbench 09:18:39 PM 0 - 1352 15824.75 108979.21 |__sysbench 09:18:39 PM 0 1354 - 0.99 0.00 kworker/0:0 09:18:39 PM 0 - 1354 0.99 0.00 |__kworker/0:0 09:18:39 PM 0 1355 - 0.99 0.00 pidstat 09:18:39 PM 0 - 1355 0.99 0.00 |__pidstat
https://blog.csdn.net/qq_34556414/article/details/107094209
https://www.infoq.cn/article/9cau15oh0n7y_wktrjbi