背景
- 线上有N台机器配置一样,程序版本一样,但其中有一台机器会出现Content Switch上下文切换高的情况,其他机器并不会, 每台机器业务量差不多一致
相关知识点
上下文切换(context switch)
说明
- Linux 是一个多任务操作系统,它支持远大于 CPU 数量的任务同时运行
- 这些任务不是同时运行,而是系统在很短的时间内,将CPU轮流分配给它们,造成多任务同时运行的错觉
- 在每个任务运行前,CPU都需要知道任务从哪里加载、又从哪里开始运行,需要系统事先帮它设置好CPU 寄存器和程序计数器(Program Counter,PC)
- CPU 寄存器,是 CPU 内置的容量小、但速度极快的内存
- 程序计数器,用来存储 CPU 正在执行的指令位置、或者即将执行的下一条指令位置
- CPU 在运行任何任务前,必须的依赖环境,叫做 CPU 上下文
- CPU 上下文切换就是先把前一个任务的 CPU 上下文(也就是 CPU 寄存器和程序计数器)保存起来
- 然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。
- 保存下来的上下文,会存储在系统内核中,并在任务重新调度执行时再次加载进来
- 这样能保证任务原来的状态不受影响,让任务看起来还是连续运行
场景
进程上下文切换
- Linux 按照特权等级
- 内核空间(Ring 0)具有最高权限,可以直接访问所有资源
- 用户空间(Ring 3)只能访问受限资源,不能直接访问内存等硬件设备,必须通过系统调用陷入到内核中,才能访问这些特权资源。
- 进程既可以在用户空间运行,也可以在内核空间中运行
- 进程在用户空间运行时称为进程的用户态
- 进程在内核空间运行时称为进程的内核态
- 从用户态到内核态的转变,需要通过系统调用来完成
- 进程切换时才需要切换上下文
线程上下文切换
- 线程是调度的基本单位,而进程则是资源拥有的基本单位
- 当进程拥有多个线程时,这些线程会共享相同的虚拟内存和全局变量等资源。这些资源在上下文切换时是不需要修改的
- 线程也有自己的私有数据,比如栈和寄存器等,这些在上下文切换时也是需要保存的
- 线程的上下文切换其实就可以分为两种情况:
- 前后两个线程属于不同进程。因为资源不共享,所以切换过程就跟进程上下文切换是一样
- 前后两个线程属于同一个进程。因为虚拟内存是共享的,所以在切换时,虚拟内存这些资源就保持不动,只需要切换线程的私有数据、寄存器等不共享的数据
- 虽然同为上下文切换,但同进程内的线程切换,要比多进程间的切换消耗更少的资源
中断上下文切换
- 为了快速响应硬件的事件,中断处理会打断进程的正常调度和执行,转而调用中断处理程序,响应设备事件
工具
vmstat
- vmstat 使用说明
vmstat用于分析系统的内存使用情况,也可以分析 CPU 上下文切换和中断的次数, 正在运行和等待 CPU 的进程数过多,导致了大量的上下文切换,而上下文切换又导致了系统 CPU 的占用率升高
常用命令
1 | bash复制代码# 每隔5秒输出1组数据 |
输出说明
- cs(context switch)是每秒上下文切换的次数
- in(interrupt)则是每秒中断的次数, 如果比较大可能有问题
- r(Running or Runnable)是就绪队列的长度,也就是正在运行和等待 CPU 的进程数, 大于CPU数, 说明有大量竞争
- b(Blocked)则是处于不可中断睡眠状态的进程数
- us(user)用户进程执行时间百分比(user time)
- sy(system)内核系统进程执行时间百分比(system time)
pidstat
- pidstat 使用说明
pidstat用于查看每个进程的详细情况 - 安装
1 | arduino复制代码apt-get install sysstat |
常用命令
1 | bash复制代码# 每隔5秒输出1组数据 |
输出说明
- cswch表示每秒自愿上下文切换(voluntary context switches)的次数
- 自愿上下文切换是指进程无法获取所需资源,导致的上下文切换
- I/O、内存等系统资源不足时会发生自愿上下文切换
- 自愿上下文切换变多了,说明进程都在等待资源,有可能发生了 I/O 等其他问题
- nvcswch表示每秒非自愿上下文切换(non voluntary context switches)的次数。
- 非自愿上下文切换是指进程由于时间片已到等原因,被系统强制调度,进而发生的上下文切换
- 大量进程都在争抢 CPU 时就容易发生非自愿上下文切换
- 非自愿上下文切换变多了,说明进程都在被强制调度,也就是都在争抢 CPU,说明 CPU 的确成了瓶颈;
中断 /proc/interrupts
- /proc 是 Linux 的一个虚拟文件系统,用于内核空间与用户空间之间的通信
- /proc/interrupts 是通信机制的一部分,提供了一个只读的中断使用情况
- 中断次数变多说明 CPU 被中断处理程序占用,可以通过查看 /proc/interrupts 文件来分析具体的中断类型
查看命令
1 | bash复制代码# -d 参数表示高亮显示变化的区域 |
排查过程
- 查找上下文切换高的程序
- 使用vmstat命令观察系统in(中断),cs(上下文切换)情况,发现这两个数值比机器机器都要高一些
- 猜测某一个程序有问题
- 使用pidstat命令观察所有的进程情况,发现有问题机器的%usr比%system数值一般要大,而且持续时间比较长,正常的机器就不会
- 猜测程序多数情况下不断地在用户空间和内核空间之间切换,导致上下文切换高
- 查看上下文切换高的程序文档(业务关系这里忽略程序名称,程序是github上开源的),发现程序不能在内核空间上使用时会回退到用户空间
- 解决方法
- 查看linux系统当前加载的模块 lsmod, 发现有问题的机器并没有正确加载到程序的内核模块,而正常的机器有
- 查看当前linux系统内核版本 uname -r, 发现系统内核版本和其他机器不一致
- 查看当前下载过的内核 dpkg –list | grep linux-image, 发现系统内核被更新过,原来程序内核模块没有正常加载,导致使用用户空间
- 最后禁用内核更新,重新编译程序安装
本文转载自: 掘金