
CPU使⽤率低负载⾼的原因
原因总结
产⽣的原因⼀句话总结就是:等待磁盘I/O完成的进程过多,导致进程队列长度过⼤,但是cpu运⾏的进程却很少,这样就体现到负载过⼤了,cpu使⽤率低。
下⾯内容是具体的原理分析:
在分析负载为什么⾼之前先介绍下什么是负载、多任务操作系统、进程调度等相关概念。
什么是负载
什么是负载:负载就是cpu在⼀段时间内正在处理以及等待cpu处理的进程数之和的统计信息,也就是cpu使⽤队列的长度统计信息,这个数字越⼩越好(如果超过CPU核⼼*0.7就是不正常)
负载分为两⼤部分:CPU负载、IO负载
例如,假设有⼀个进⾏⼤规模科学计算的程序,虽然该程序不会频繁地从磁盘输⼊输出,但是处理完成需要相当长的时间。因为该程序主要被⽤来做计算、逻辑判断等处理,所以程序的处理速度主要依赖于cpu的计算速度。此类cpu负载的程序称为“计算密集型程序”。
还有⼀类程序,主要从磁盘保存的⼤量数据中搜索找出任意⽂件。这个搜索程序的处理速度并不依赖于cpu,⽽是依赖于磁盘的读取速度,也就是输⼊输出(input/output,I/O).磁盘越快,检索花费的时间就越短。此类I/O负载的程序,称为“I/O密集型程序”。
什么是多任务操作系统
Linux操作系统能够同时处理⼏个不同名称的任务。但是同时运⾏多个任务的过程中,cpu和磁盘这些有限的硬件资源就需要被这些任务程序共享。即便很短的时间间隔内,需要⼀边在这些任务之间进⾏切换到⼀边进⾏处理,这就是多任务。
运⾏中的任务较少的情况下,系统并不是等待此类切换动作的发⽣。但是当任务增加时,例如任务A正在CPU上执⾏计算,接下来如果任务B和C也想进⾏计算,那么就需要等待CPU空闲。也就是说,即便是运⾏处理某任务,也要等到轮到他时才能运⾏,此类等待状态就表现为程序运⾏延迟。
uptime输出中包含“load average”的数字
[root@localhost ~]# uptime
11:16:38 up 2:06, 4 urs, load average: 0.00, 0.02, 0.05
Load average从左边起依次是过去1分钟、5分钟、15分钟内,单位时间的等待任务数,也就是表⽰平均有多少任务正处于等待状态。在load average较⾼的情况下,这就说明等待运⾏的任务较多,因此轮到该任务运⾏的等待时间就会出现较⼤的延迟,即反映了此时负载较⾼。
进程调度
什么是进程调度:
进程调度也被⼀些⼈称为cpu上下⽂切换意思是:CPU切换到另⼀个进程需要保存当前进程的状态并恢复另⼀个进程的状态:当前运⾏任务转为就绪(或者挂起、中断)状态,另⼀个被选定的就绪任务成为当前任务。进程调度包括保存当前任务的运⾏环境,恢复将要运⾏任务的运⾏环境。
在linux内核中,每⼀个进程都存在⼀个名为“进程描述符”的管理表。该进程描述符会调整为按照优先级降序排序,已按合理的顺序运⾏进程(任务)。这个调整即为进程调度器的⼯作。
调度器划分并管理进程的状态,如:
等待分配cpu资源的状态。
等待磁盘输⼊输出完毕的状态。
下⾯在说⼀下进程的状态区别:
状态说明
运⾏态(running)只要cpu空闲,任何时候都可以运⾏
可中断睡眠(interruptible)为恢复时间⽆法预测的长时间等待状态。如,来⾃于键盘设备的输⼊。
不可中断睡眠:
(uninterruptible)主要为短时间时的等待状态。例如磁盘输⼊输出等待。被IO阻塞的进程
就绪态(runnable)响应暂停信号⽽运⾏的中断状态。
僵死态(zombie)进程都是由⽗进程创建,并销毁;在⽗进程没有销毁其⼦进程,被销毁的时候,其⼦进程由于没有⽗进程被销毁,就会转变为僵死态。
状态说明
下⾯举例来说明进程状态转变:
这⾥有三个进程A、B、C同时运⾏。⾸先,每个进程在⽣成后都是可运⾏状态,也就是running状态的开始,⽽不是现在运⾏状态,由于在linux内核中⽆法区别正在运⾏的状态和可运⾏的等待状态,下⾯将可运⾏状态和正在运⾏状态都称为running状态。
进程A:running
进程B:running
进程C:running
running的三个进程⽴即成为调度对象。此时,假设调度器给进程A分配了CPU的运⾏权限。
进程A:running (正在运⾏)
进程B:running
进程C:running
进程A分配了CPU,所以进程A开始处理。进程B和C则在此等待进程A迁出CPU。假设进程A进⾏若⼲计算之后,需要从磁盘读取数据。那么在A发出读取磁盘数据的请求之后,到请求数据到达之前,将
不进⾏任何⼯作。此状态称为“因等待I/O操作结束⽽被阻塞”。在I/O完成处理前,进程A就⼀直处于等待中,就会转为不可中断睡眠状态(uninterruptible),并不使⽤CPU。于是调度器查看进程B和进程C的优先级计算结果,将CPU运⾏权限交给优先级较⾼的⼀⽅。这⾥假设进程B的优先级⾼于进程C。
进程A:uninterruptible (等待磁盘输⼊输出/不可中断状态)
进程B:running (正在运⾏)
进程C:running
进程B刚开始运⾏,就需要等待⽤户的键盘输⼊。于是B进⼊等待⽤户键盘输⼊状态,同样被阻塞。结果就变成了进程A和进程B都是等待输出,运⾏进程C。这时进程A和进程B都是等待状态,但是等待磁盘输⼊输出和等待键盘输⼊为不同的状态。等待键盘输⼊是⽆限期的事件等待,⽽读取磁盘则是必须短时间内完成的事件等待,这是两种不同的等待状态。各进程状态如下所⽰:
进程A:uninterruptible (等待磁盘输⼊输出/不可中断状态)
进程B:interruptible (等待键盘输⼊输出/可中断状态)
进程C:running (正在运⾏)
这次假设进程C在运⾏的过程中,进程A请求的数据从磁盘到达了缓冲装置。紧接着硬盘对内核发起中断信号,内核知道磁盘读取完成,将进程A恢复为可运⾏状态。
进程A:running (正在运⾏)进程B:interruptible (等待键盘输⼊输出/可中断状态)进程C:running (正在运⾏)
此后进程C也会变为某种等待状态。如CPU的占⽤时间超出了上限、任务结束、进⼊I/O等待。⼀旦满⾜这些条件,调度器就可以完成从进程C到进程A的进程状态切换。
负载的意义
负载表⽰的是“等待进程的平均数”。在上⾯的进程状态变换过程中,除了running状态,其他都是等待状态,那么其他状态都会加⼊到负载等待进程中吗?
事实证明,只有进程处于运⾏态(running)和不可中断状态(interruptible)才会被加⼊到负载等待进程中,也就是下⾯这两种情况的进程才会表现为负载的值。
即便需要⽴即使⽤CPU,也还需等待其他进程⽤完CPU
即便需要继续处理,也必须等待磁盘输⼊输出完成才能进⾏
下⾯描述⼀种直观感受的场景说明为什么只有运⾏态(running)和可中断状态(interruptible)才会被加⼊负载。
如:在很占⽤CPU资源的处理中,例如在进⾏动画编码的过程中,虽然想进⾏其他相同类型的处理,结果系统反映却变得很慢,还有从磁盘读取⼤量数据时,系统的反映也同样会变的很慢。但是另⼀⽅⾯,⽆论有多少等待键盘输⼊输出操作的进程,也不会让系统响应变慢。
什么场景会造成CPU低⽽负载确很⾼?
通过上⾯的具体分析负载的意义就很明显了,负载总结为⼀句话就是:需要运⾏处理但⼜必须等待队列前的进程处理完成的进程个数。具体来说,也就是如下两种情况:
等待被授权予CPU运⾏权限的进程
等待磁盘I/O完成的进程
cpu低⽽负载⾼也就是说等待磁盘I/O完成的进程过多,就会导致队列长度过⼤,这样就体现到负载过⼤了,但实际是此时cpu被分配去执⾏别的任务或空闲,具体场景有如下⼏种。
场景⼀:磁盘读写请求过多就会导致⼤量I/O等待上⾯说过,cpu的⼯作效率要⾼于磁盘,⽽进程在cpu上
⾯运⾏需要访问磁盘⽂件,这个时候cpu会向内核发起调⽤⽂件的请求,让内核去磁盘取⽂件,这个时候会切换到其他进程或者空闲,这个任务就会转换为不可中断睡眠状态。当这种读写请求过多就会导致不可中断睡眠状态的进程过多,从⽽导致负载⾼,cpu低的情况。
场景⼆:MySQL中存在没有索引的语句或存在死锁等情况我们都知道MySQL的数据是存储在硬盘中,如果需要进⾏sql查询,需要先把数据从磁盘加载到内存中。当在数据特别⼤的时候,如果执⾏的sql语句没有索引,就会造成扫描表的⾏数过⼤导致I/O阻塞,或者是语句中存在死锁,也会造成I/O阻塞,从⽽导致不可中断睡眠进程过多,导致负载过⼤。
具体解决⽅法可以在MySQL中运⾏show full processlist命令查看线程等待情况,把其中的语句拿出来进⾏优化。
场景三:外接硬盘故障,常见有挂了NFS,但是NFS rver故障⽐如我们的系统挂载了外接硬盘如NFS共享存储,经常会有⼤量的读写请求去访问NFS存储的⽂件,如果这个时候NFS Server故障,那么就会导致进程读写请求⼀直获取不到资源,从⽽进程⼀直是不可中断状态,造成负载很⾼。
--------------------
常见的处理办法
⽹站相关进程导致负载⾼处理办法:
1、直接把⽹站php或http或tomcat等⽹站服务重启,很多时候负载就降下来了
2、也可能是⽹站代码漏洞导致的,需要反馈开发⼀起查找原因和处理
3、把重复的tomcat kill全部掉重新启动
mysql进程导致的负载⾼处理办法:
1、常见的就是mysql慢查询导致,可以在mysql慢查询⽇志找到相关sql语句,这需要对sql进⾏优化
2、还可以进⼊mysql,⽤show full processlist\G;查看那个mysql进程执⾏时间⽐较久的慢查询。如果是内部后台使⽤的语句,可以先kill掉,优化后再执⾏。
3、mysql读写太频繁,如果是读写频繁可以在%wa等待输⼊输出看的出来占⽤cpu百分⽐很⼤。也可以通过命令iostat查看系统读写情况。
还有可能是⽹络原因,系统硬件原因等