04-基础篇:经常说的 CPU 上下文切换是什么意思?(下)





怎么查看系统的上下文切换情况

过多的上下文切换,会把CPU时间消耗在寄存器、内核栈以及虚拟内存等数据的保存和恢复上
缩短进程真正运行的时间,成了系统性能大幅下降的一个元凶


vmstat是一个常用的系统性能分析工具,主要用来分析系统的内存使用情况,也常用来分析CPU上下文切换和中断的次数
# 每隔5秒输出1组数据
[root@local_sa_192-168-1-6 ~]# vmstat 5
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 2549872   2112 842612    0    0     0     0   41   73  0  0 100  0  0
 
# 输出结果解析
# cs(context switch)是每秒上下文切换的次数
# in(interrupt)则是每秒中断的次数
# r(Running or Runnable)是就绪队列的长度,也就是正在运行和等待CPU的进程数
# b(Blocked)则是处于不可中断睡眠状态的进程数
可以看到,这个例子中的上下文切换次数cs是73次,而系统中断次数in则是41次,而就绪队列长度r和不可中断状态进程数b都是0



pidstat
vmstat只给出了系统总体的上下文切换情况,要想查看每个进程的详细情况,就需要使用pidstat
加上-w选项,就可以查看每个进程上下文切换的情况了
# 每隔5秒输出1组数据
[root@local_sa_192-168-1-6 ~]# pidstat -w 5
Linux 3.10.0-1160.31.1.el7.x86_64 (local_sa_192-168-1-6) 	2021年11月09日 	_x86_64_	(2 CPU)

16时02分50秒   UID       PID   cswch/s nvcswch/s  Command
16时02分55秒     0         6      0.60      0.00  ksoftirqd/0
16时02分55秒     0         9      3.98      0.00  rcu_sched
16时02分55秒     0        11      0.20      0.00  watchdog/0
16时02分55秒     0        12      0.20      0.00  watchdog/1
16时02分55秒     0        35      0.20      0.00  khugepaged
......
平均时间:   UID       PID   cswch/s nvcswch/s  Command
平均时间:     0         6      0.60      0.00  ksoftirqd/0
平均时间:     0         9      3.98      0.00  rcu_sched
平均时间:     0        11      0.20      0.00  watchdog/0
平均时间:     0        12      0.20      0.00  watchdog/1
平均时间:     0        35      0.20      0.00  khugepaged
......

# 输出结果分析
这个结果中有两列内容是重点关注对象。
一个是cswch,表示每秒自愿上下文切换(voluntary context switches)的次数,
一个是nvcswch,表示每秒非自愿上下文切换(non voluntary context switches)的次数

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

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




案例

将使用sysbench来模拟系统多线程调度切换的情况

sysbench是一个多线程的基准测试工具,一般用来评估不同系统参数下的数据库负载情况
当然,在这次案例中,我们只把它当成一个异常进程来看,作用是模拟上下文切换过多的问题

预先安装sysbench和sysstat包
[root@local_sa_192-168-1-6 ~]# yum install sysbench sysstat -y


1.在第一个终端先用 vmstat 看一下空闲系统的上下文切换次数

# 间隔1秒输出1组数据
[root@local_sa_192-168-1-6 ~]# 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
 0  0      0 2462268   2112 929712    0    0     5    17   39  75  1  0 99  0  0
 
 # 上下文切换次数cs是75
 # 中断次数in是39
 # r和b都是0。因为这会儿没有运行其他任务,所以它们就是空闲系统的上下文切换次数
 

2.然后再在第一个终端运行sysbench,模拟系统多线程调度的瓶颈

# 以10个线程运行5分钟的基准测试,模拟多线程切换的问题
[root@local_sa_192-168-1-6 ~]# sysbench --threads=10 --max-time=300 threads run
......
Threads started!

3.在第二个终端运行 vmstat ,观察上下文切换情况

# 每隔1秒输出1组数据,如果要停止 ctrl+c
[root@local_sa_192-168-1-6 ~]# 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
 8  0      0 2459604   2112 929964    0    0     0     0 36236 732600 25 73  2  0  0
 
#可以发现
#cs列的上下文切换次数从之前的75骤然上升到了73万
#r列就绪队列的长度已经到了8,远远超过了系统CPU的个数2,所以肯定会有大量的CPU竞争
#us和sy列这两列的CPU使用率加起来上升到了98%,其中系统CPU使用率,也就是sy列高达73%,说明CPU主要是被内核占用了
#in列中断次数也上升到了3万左右,说明中断处理也是个潜在的问题

综合这几个指标,我们可以知道,系统的就绪队列过长,也就是正在运行和等待CPU的进程数过多
导致了大量的上下文切换,而上下文切换又导致了系统CPU的占用率升高


4.在第三个终端再用pidstat来看一下,CPU和进程上下文切换的情况

那么到底是什么进程导致了这些问题呢?

pidstat
# 每隔1秒输出1组数据
# -w参数表示输出进程上下文切换指标
# -u参数表示输出cpu使用指标
[root@local_sa_192-168-1-6 ~]# pidstat -w -u 1
Linux 3.10.0-1160.31.1.el7.x86_64 (local_sa_192-168-1-6) 	2021年11月09日 	_x86_64_	(2 CPU)

16时20分34秒   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
16时20分35秒     0     31005   49.00  147.00    0.00    0.00  196.00     1  sysbench
16时20分35秒     0     31100    0.00    1.00    0.00    0.00    1.00     0  pidstat

16时20分34秒   UID       PID   cswch/s nvcswch/s  Command
16时20分35秒     0         6      2.00      0.00  ksoftirqd/0
16时20分35秒     0         9     15.00      0.00  rcu_sched
16时20分35秒     0       398     20.00      0.00  xfsaild/dm-0
16时20分35秒     0       671      1.00      0.00  irqbalance
16时20分35秒     0      1378      1.00      0.00  teamviewerd
16时20分35秒    42      7678      1.00      0.00  gsd-color
16时20分35秒  1003     30259      1.00      0.00  sshd
16时20分35秒     0     30970      3.00      0.00  kworker/0:2
16时20分35秒     0     30995      1.00      0.00  kworker/1:1
16时20分35秒     0     31100      1.00      1.00  pidstat

#从pidstat的输出可以发现,CPU使用率的升高果然是sysbench导致的,它的CPU使用率已经达到了196%(2核)
#从上面输出来看,切换次数加起来也就不到一百,比vmstat的73万明显小了太多,这是怎么回事呢?难道是工具本身出了错吗?

pidstat
#-t参数表示输出线程的上下文切换指标
[root@local_sa_192-168-1-6 ~]# pidstat -w -t  1
Linux 3.10.0-1160.31.1.el7.x86_64 (local_sa_192-168-1-6) 	2021年11月09日 	_x86_64_	(2 CPU)

16时28分19秒   UID      TGID       TID   cswch/s nvcswch/s  Command
16时28分21秒     0     31143         -      3.00      0.00  kworker/1:2
16时28分21秒     0         -     31143      3.00      0.00  |__kworker/1:2
16时28分21秒     0     31165         -      5.00      0.00  kworker/0:1
16时28分21秒     0         -     31165      5.00      0.00  |__kworker/0:1
16时28分21秒     0         -     31187  14431.00  50613.00  |__sysbench
16时28分21秒     0         -     31188  13076.00  68666.00  |__sysbench
16时28分21秒     0         -     31189  12610.00  53644.00  |__sysbench
16时28分21秒     0         -     31190  11191.00  64400.00  |__sysbench
16时28分21秒     0         -     31191  17173.00  55407.00  |__sysbench
16时28分21秒     0         -     31192  12016.00  44366.00  |__sysbench
16时28分21秒     0         -     31193  12941.00  57103.00  |__sysbench
16时28分21秒     0         -     31194  11404.00  64440.00  |__sysbench
16时28分21秒     0         -     31195   9976.00  60912.00  |__sysbench
16时28分21秒     0         -     31196  16295.00  69772.00  |__sysbench


# 看来,上下文切换罪魁祸首,还是过多的sysbench线程


我们已经找到了上下文切换次数增多的根源,那是不是到这儿就可以结束了呢?
当然不是。不知道你还记不记得,前面在观察系统指标时,除了上下文切换频率骤然升高,
还有一个指标也有很大的变化。
是的,正是中断次数。中断次数也上升到了3万,
但到底是什么类型的中断上升了,现在还不清楚。我们接下来继续抽丝剥茧找源头


从/proc/interrupts这个只读文件中读取。
/proc实际上是Linux的一个虚拟文件系统,用于内核空间与用户空间之间的通信。
/proc/interrupts就是这种通信机制的一部分,提供了一个只读的中断使用情况

# -d 高亮显示变化的区域
[root@local_sa_192-168-1-6 ~]# watch  -d  cat /proc/interrupts
Every 2.0s: cat /proc/interrupts                                                                                                                           Tue Nov  9 16:31:48 2021

           CPU0       CPU1
......
LOC:    3343255    2547098   Local timer interrupts
SPU:          0          0   Spurious interrupts
PMI:          0          0   Performance monitoring interrupts
IWI:	  42561      41437   IRQ work interrupts
RTR:          0          0   APIC ICR read retries
RES:    8119837    8192688   Rescheduling interrupts
......

观察一段时间,发现变化速度最快的是重调度中断(RES)
这个中断类型表示,唤醒空闲状态的CPU来调度新的任务运行
这是多处理器系统(SMP)中,调度器用来分散任务到不同CPU的机制
通常也被称为处理器间中断(Inter-ProcessorInterrupts,IPI)

所以,这里的中断升高还是因为过多任务的调度问题,跟前面上下文切换次数的分析结果是一致的




小结

每秒上下文切换多少次才算正常呢?
这个数值其实取决于系统本身的CPU性能
如果系统的上下文切换次数比较稳定,那么从数百到一万以内,都应该算是正常的
但当上下文切换次数超过一万次,或者切换次数出现数量级的增长时,就很可能已经出现了性能问题

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


posted @ 2021-11-09 17:38  李成果  阅读(257)  评论(0编辑  收藏  举报