欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

探讨一次上下文切换的高排查经历

最编程 2024-08-14 18:28:50
...

背景

  • 线上有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 的占用率升高

常用命令

# 每隔5秒输出1组数据
vmstat 5

# 格式化数据对齐
vmstat 1 3 | column -t

输出说明

  • cs(context switch)是每秒上下文切换的次数
  • in(interrupt)则是每秒中断的次数, 如果比较大可能有问题
  • r(Running or Runnable)是就绪队列的长度,也就是正在运行和等待 CPU 的进程数, 大于CPU数, 说明有大量竞争
  • b(Blocked)则是处于不可中断睡眠状态的进程数
  • us(user)用户进程执行时间百分比(user time)
  • sy(system)内核系统进程执行时间百分比(system time)

pidstat

  • pidstat 使用说明 pidstat用于查看每个进程的详细情况
  • 安装
apt-get install sysstat

常用命令

# 每隔5秒输出1组数据
pidstat -w -u 5

# 指定进程名
# -w参数表示输出进程切换指标,-u参数则表示输出CPU使用指标,  -t参数输出线程的指标
pidstat -w -u -t -C "进程名" 3

输出说明

  • 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 文件来分析具体的中断类型

查看命令

# -d 参数表示高亮显示变化的区域
watch -d cat /proc/interrupts

排查过程

  • 查找上下文切换高的程序
    • 使用vmstat命令观察系统in(中断),cs(上下文切换)情况,发现这两个数值比机器机器都要高一些
    • 猜测某一个程序有问题
    • 使用pidstat命令观察所有的进程情况,发现有问题机器的%usr比%system数值一般要大,而且持续时间比较长,正常的机器就不会
    • 猜测程序多数情况下不断地在用户空间和内核空间之间切换,导致上下文切换高
    • 查看上下文切换高的程序文档(业务关系这里忽略程序名称,程序是github上开源的),发现程序不能在内核空间上使用时会回退到用户空间
  • 解决方法
    • 查看linux系统当前加载的模块 lsmod, 发现有问题的机器并没有正确加载到程序的内核模块,而正常的机器有
    • 查看当前linux系统内核版本 uname -r, 发现系统内核版本和其他机器不一致
    • 查看当前下载过的内核 dpkg --list | grep linux-image, 发现系统内核被更新过,原来程序内核模块没有正常加载,导致使用用户空间
    • 最后禁用内核更新,重新编译程序安装

推荐阅读