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文件来分析具体的中断类型
转载请注明出处哟~
https://www.cnblogs.com/lichengguo