Linux中CPU平均负载
Linux平均负载
在Linux中load average的进程包括三种状态的进程,Running(正在使用CPU的进程),Runnable(正在等待CPU的进程),Uninterruptible sleep(不可中断的进程,状态标记为"D",某些工具标记状态为"b"表示为blocked)。前面两种可以统一称为CPU可执行队列中的进程(on run queue),各类进程状态查看工具一般标记该状态为"R"。
所以查看当前时间load中包含的进程可以用以下命令
ps -aux | awk '$8 ~ "D" || $8 ~ "R"'
ps stat介绍
D uninterruptible sleep (usually IO) //无法中断的休眠状态(通常 IO 的进程);
R running or runnable (on run queue) //正在运行可中在队列中可过行的;
S interruptible sleep (waiting for an event to complete) //处于休眠状态;
T stopped by job control signal //停止或被追踪;
W paging (not valid since the 2.6.xx kernel) //进入内存交换 (从内核2.6开始无效);
X dead (should never be seen) //死掉的进程 (不应该出现);
Z defunct ("zombie") process, terminated but not reaped by its parent //僵尸进程;
For BSD formats and when the stat keyword is used, additional characters may be displayed:
< high-priority (not nice to other users) //优先级高的进程
N low-priority (not nice to other users) //优先级较低的进程
L has pages locked into memory (for real-time and custom IO) //有些页被锁进内存;
s is a session leader //进程的领导者(在它之下有子进程);
l is multi-threaded //多线程,克隆线程(使用 CLONE_THREAD, 类似 NPTL pthreads);
+ is in the foreground process group //位于后台的进程组;
Uninterruptible Sleep
Linux上的 load average 除了包括正在使用CPU的进程数量和正在等待 CPU 的进程数量之外,还包括 uninterruptible sleep 的进程数量。通常等待 IO 设备、等待网络的时候,进程会处于 uninterruptible sleep 状态。Linux 设计者的逻辑是,uninterruptible sleep 应该都是很短暂的,很快就会恢复运行,所以被等同于 runnable。然而uninterruptible sleep 即使再短暂也是 sleep,何况现实世界中 uninterruptible sleep 未必很短暂,大量的、或长时间的 uninterruptible sleep 通常意味着 IO 设备遇到了瓶颈。众所周知,sleep 状态的进程是不需要 CPU 的,即使所有的 CPU 都空闲,正在 sleep 的进程也是运行不了的,所以 sleep 进程的数量绝对不适合用作衡量 CPU 负载的指标,Linux 把 uninterruptible sleep 进程算进 load average 的做法直接颠覆了 load average 的本来意义。所以在 Linux 系统上,load average 这个指标基本失去了作用,因为你不知道它代表什么意思,当看到 load average 很高的时候,你不知道是 runnable 进程太多还是 uninterruptible sleep 进程太多,也就无法判断是 CPU 不够用还是 IO 设备有瓶颈。
Executing process requests some service from kernel,
\ kernel suspends process and moves it to a parking queue
\
\ Kernel completes the service,
\ \ kernel moves suspended process to one of the runnable queues
\ \
\ \ Suspended process moves to top of runnable queue,
\ \ \ kernel resumes the process execution
\ \ \
Running --;--> Parked --;--> Runnable --;--> Running
1)内核 每隔一段时间都会统一接受所有进程的请求(这里可能与CPU时间片有关系,需要进一步确认),如果发现有进程发起了请求,首先内核会去获取进程所需要的资源,然后把这个进程暂时放到一个 parking 队列里;这里类似于需求收集阶段。2)在需求收集结束后,会把发起请求的进程放到一个runnable 队列里,等待执行。3)把 runnable 队列里的进程依次执行。
进程的 D 状态(Uninterruptible Sleep)发生在需求收集阶段。试想在这个阶段,当内核去获取进程所需要的资源的时候,比如从磁盘读取某一个文件,这个时候突然磁盘驱动不干活了(可能因为取的数据太多驱动没反应过来,也可能因为磁盘出了故障),这个时候内核就为难了,场面变得比较尴尬。1)首先驱动是工作在内核态的,内核对驱动有绝对的信任权;其次,2)进程发起请求了,自己作为老大于情于理都应该应承;3)但是进程所要求的数据实在拿不到怎么办呢?4)这个时候内核只能把进程的状态临时转换为 D 状态,标明这个锅是内核自己的,内核正在尝试获取进程需要的资源,而且获取资源的途径是内核可控的(内核必须对全局的资源拥有控制权限,否则也不要当内核了)如果进程所需要的数据很快就被内核拿到了还好(大部分情况下都是如此),进程会从 D 状态转到可运行的状态;如果拿不到(比如真的磁盘出现了故障,而驱动代码又没有考虑到这种情况,或者驱动抛出了信号但是内核不承认),那么相应的进程就会一直处于 D 状态。非常戏剧性的是,只有处于可运行状态(Runnable)的进程可以接受终止信号( kill 信号),处于 D 状态的进程是没有办法被 kill 掉的;这也让终止 D 状态的进程变得复杂——必须重启服务器才能把 D 状态的进程杀掉
Comments | NOTHING