Linux性能优化实战CPU篇(一)

一、优化方向

1,性能指标

  从应用负载的视角出发,考虑“吞吐”和“延时”

  从系统资源的视角出发,考虑资源使用率、饱和度等

  

2,性能优化步骤

  • 选择指标评估应用程序和系统的性能;
  • 为应用程序和系统设置性能目标;
  • 进行性能基准测试;
  • 性能分析定位瓶颈;
  • 优化系统和应用程序;
  • 性能监控和告警。

3,Linux性能工具图谱

二、平均负载

1,stress

安装命令:apt install stress
  stress 是一个linux系统压力测试工具,这里我们用作异常进程模拟平均负载升高场景
#模拟一个CPU使用率 100%  stress -c N 会让stress生成N个工作进程进行开方运算,以此对CPU产生负载。
stress --cpu 1 --timeout 600
#模拟I/O密集进程 stress -i N  会产生N个进程,每个进程反复调用sync()将内存上的内容写到硬盘上, --timeout 600 表示600秒后退出 stress -i 1 --timeout 600

2,sysstat

安装命令:apt install sysstat
sysstat 是一个常用的linux性能工具,用来监控和分析系统的性能。
  • mpstat 是一个常用的多核cpu性能分析工具,用来实时查看每个CPU的性能指标,以及所有CPU的平均指标 
  • mpstat -P ALL 5   
    其中-P ALL  表示监控所有CPU
    数字5,表示每间隔5秒输出一组数据
  • pidstat 是一个常用的进程性能分析工具,用来实时查看进程的CPU、内存、IO以及上下文切换等性能指标
  • pidstat -u 5 1
    每间隔5秒输出一组数据

  pid参数详解  

-u:默认的参数,显示各个进程的cpu使用统计
-r:显示各个进程的内存使用统计
-d:显示各个进程的IO使用情况
-p:指定进程号
-w:显示每个进程的上下文切换情况
-t:显示选择任务的线程的统计信息外的额外信息
-T { TASK | CHILD | ALL }
这个选项指定了pidstat监控的。TASK表示报告独立的task,CHILD关键字表示报告进程下所有线程统计信息。ALL表示报告独立的task和task下面的所有线程。
注意:task和子线程的全局的统计信息和pidstat选项无关。这些统计信息不会对应到当前的统计间隔,这些统计信息只有在子线程kill或者完成的时候才会被收集。
-V:版本号
-h:在一行上显示了所有活动,这样其他程序可以容易解析。
-I:在SMP环境,表示任务的CPU使用率/内核数量
-l:显示命令名和所有参数

3,场景模拟

a>CPU密集

  stress

#模拟一个CPU使用率 100%  stress -c N 会让stress生成N个工作进程进行开方运算,以此对CPU产生负载。--timeout 600 表示600秒后退出 
stress --cpu 1 --timeout 600

  监控uptime,负载在升高

  mpstat,发现一个CPU的使用率高达100%,但是iowait为0,说明平均负载的升高由于CPU的使用率为100%

   pidstat,发现是stress进程导致CPU使用率升高

 

b>I/O密集

  stress

#模拟I/O密集进程  stress -i N  会产生N个进程,每个进程反复调用sync()将内存上的内容写到硬盘上
stress -i 1 --timeout 600

  监控uptime,负载在升高

  mpstat,发现一个系统CPU使用率升至23.87%,iowait高达67.53% 。说明平均负载的升高由于iowait的升高

  

  

  pidstat,发现是由于stress进程导致

c>大量进程的场景

  stress

stress -c 8 --timeout 600

  uptime

  pidstat,发现8个进程在争抢2个CPU,每个进程等待CPU的时间高达75%,导致CPU过载

三、CPU的上下文切换

1,基本概念

  CPU寄存器:CPU内置的容量小、但速度极快的内存

  程序计数器:用于存储CPU正在执行的指令位置、或者即将执行的下一条指令位置

  CPU上下文:CPU寄存器和程序计数器所必须的依赖环境

  CPU上下文切换:先把前一个任务的CPU上下文(也就是CPU寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。

2,分类

a>进程上下文切换

  Linux按照特权等级,把进程的运行空间分为内核空间和用户空间,分别对应CPU特权等级的 Ring 0 和Ring 3

  • 内核空间(Ring 0)具有最高权限,可以直接访问所有资源
  • 用户空间(Ring 3)只能访问受限资源,不能直接访问内存等硬件设备,必须通过系统调用陷入内核中,才能访问这些特权资源

  

  换个角度,也就是进程既可以在用户空间运行,又可以在内核空间运行。进程在用户空间运行时,被称为进程的用户态,而陷入内核空间的时候,被称为进程的内核态。

  在进程切换时才需要切换上下文,也就是进程调度时。Linux为每个CPU都维护了一个就绪队列,将活跃进程按照优先级和等待CPU的时间排序,然后选择最需要CPU的进程,也就是优先级最高和等待CPU时间最长的进程运行。涉及到的场景包括:

  • 为了保证所有进程可以得到公平调度,CPU时间被划分为一段段的时间片,这些时间片再被轮流分配给各个进程。这样,当某个进程的时间片耗尽了,就会被系统挂起,切换到其他正在等待CPU的进程运行
  • 进程在系统资源不足(比如内存不足)时,要等到资源满足后才可以运行,这个时候进程也会被挂起,并有系统调度其他进程运行
  • 当进程通过睡眠函数sleep这样的方法将自己主动挂起时,自然也会重新调度
  • 当有优先级更高的进程运行时,为了保证高优先级进程的运行,当前进程会被挂起,由高优先级进程来运行
  • 当发生硬件中断时,CPU上的进程会被中断挂起,转而执行内核中的中断服务进程

b>线程上下文切换

  线程是调度的基本单位,而进程则是资源拥有的基本单位

  • 当进程只有一个线程时,可以认为进程就等于线程
  • 当进程拥有多个线程时,这些线程会共享相同的虚拟内存和全局变量等资源。这些资源在上下文切换时不需要修改
  • 线程也有自己的私有数据,比如栈和寄存器,这些在上下文切换时也需要保存

  线程上下文切换:1,前后两个线程属于不同进程,由于资源不同就是进程上下文切换;2,前后两个线程属于同一个进程,此时虚拟内存共享,切换时只需要切换线程的私有数据、寄存器等不共享的数据。

c>中断上下文切换

  • 为了快速响应硬件的事件,中断处理会打断进程的正常调度和执行,转而调用中断处理程序,响应设备事件。而在打断其他进程时,就需要将进程当前的状态保存起来,这样在中断结束后,进程仍然可以从原来的状态恢复运行
  • 与进程上下文切换不同,中断上下文切换并不涉及进程的用户态。所以,即便中断过程打断了一个正处在用户态的进程,也不需要保存和恢复这个进程的虚拟内存、全局变量等用户态资源。中断上下文,其实只包括内核态中断服务程序执行所必需的状态,包括CPU寄存器、内核堆栈、硬件中断参数等

3,CPU上下文切换实战

a>vmstat

  

  • cs(context switch)是每秒上下文切换的次数
  • in(interrupt)是每秒中断的次数
  • r(Running or Runnable)是就绪队列的长度,也就是正在运行和等待的CPU的进程数
  • b(Blocked)是处于不可中断睡眠状态的进程数

b>pidstat

  vmstat只给出了系统总体的上下文切换情况,要想查看每个进程的详细情况,就需要使用我们pidstat。加上-w选项,则可以查看每个进程上下文切换的情况

  

  • cswch(voluntary context switches),每秒自愿上下文切换次数。指进程无法获取所需要资源,导致的上下文切换。比如:I/O、内存等系统资源不足时,就会发生自愿上下文切换。
  • nvcswch(non voluntary context switches),每秒非自愿上下文切换。指进程由于时间片已到等原因,被系统强制调度,进程发生的上下文切换。比如:大量进程都在争抢CPU时,就容易发生非自愿上下文切换。

c>案例实操

  查看系统的上下文切换次数 

 

   采用sysbench进行压测

  

  再次查看vmstat

  

   发现cs列的上下文切换数量从之前的35骤然上升到了139万多。同时,r列:就绪队列的长度为8,远超CPU的个数2,所以判定有大量的CPU竞争;us(user)和sy(system)列:这两列的CPU使用率加起来上升到了100%,其中系统CPU使用率,也就是sy列高达84%,说明CPU主要是被内核占用了;in列:中断次数也上升到1万左右,说明中断处理也是个潜在的问题。综合这几个指标,系统的就绪队列过长,也就是正在运行和等待CPU的进程数过多,导致大量的上下文切换,而上下文切换又导致系统的CPU的占用率升高。

  采用pidstat分析

  

  

  • CPU使用率升高果然是sysbench导致的,已达100%
  • 非自愿上下文切换最高的为pidstat,自愿上下文切换频率最高的线程为kworker和sshd
  • 问题:pidstat输出的上线文切换明显小于vmstat输出的上下文切换。采用man pidstat 发现,pidstat默认显示进程的指标数据,加上-t参数后,才会输出线程指标

  

  结合两次的pidstat可以看出,sysbench(主线程)的上下文切换次数看起来并不太多,但它的子线程的上下文切换次数却很多。

  采用watch观察interrupts中断

  

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

d>总结

  如果系统的上下文切换次数比较稳定,那么从数百到一万内,都应该算是正常的。当上下文切换次数超过一万次,或者切换次数出现数量级的增长时,都很可能已经出现了性能问题:

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

 

posted @ 2022-02-07 10:01  MXC肖某某  阅读(1147)  评论(1编辑  收藏  举报