CPU上下文的切换

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

原文地址:https://www.cnblogs.com/dream397/p/14544913.html