cpu负载的探讨

Posted Jenkov

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cpu负载的探讨相关的知识,希望对你有一定的参考价值。

原链接http://blog.chinaunix.net/uid-12693781-id-368837.html

摘要:确定cpu的负载的定义,帮助管理员设置cpu负载阀值,推测可能的导致cpu负载过高的原因,进而保证服务器的正常运行。
 
1.cpu负载的定义
   首先,看看cpu负载的定义。在一般情况下可以将单核心cpu的负载看成是一条单行的桥,数字1代表cpu刚好能够处理过来,即桥上能够顺利通过所有的车辆,
桥外没有等待的车辆,桥是畅通的。当超过1时表示有等待上桥的车辆,小于1时表示车辆能够快速的通过。单核心cpu就表示该cpu能够处理的事务数是1,在多核
cpu中cpu能够并行处理的事务的数量应该是cpu个数*cpu核数,而且负载数最好不要超过这个数值。例如一个4核cpu,则cpu_load最大值为4,不能长期超过4,否则会有任务没有得到及时的处理,而使系统的负载累积增高,导致系统运行缓慢。
   大多数的Unix系统中的负载只是记录那些处在运行状态和可运行状态的进程,但是Linux有所不同,它会包含那些不可中断的处于睡眠状态的进程。这时当这些进程由于I/O的阻塞而不能够运行,就可能显著的增加cpu的负载。所以在Unix和Linux下的cpu的负载的计算方法是不一样的,在设定监测值的时候也需要特别考率。
   下面从内核源码中分析cpu负载的计算根源,这里能够给出cpu负载的完整计算方法。下面的代码是是在kernel-2.6.32中的kernel/shed.c中截取的,用来计算cpu的平均负载。
 
技术分享图片
/* Variables and functions for calc_load */
static atomic_long_t calc_load_tasks;
static unsigned long calc_load_update;
unsigned long avenrun[3];
EXPORT_SYMBOL(avenrun);
 
/**
 * get_avenrun - get the load average array
 * @loads: pointer to dest load array
 * @offset: offset to add
 * @shift: shift count to shift the result left
 *
 * These values are estimates at best, so no need for locking.
 */
void get_avenrun(unsigned long *loads, unsigned long offset, int shift)
{
loads[0] = (avenrun[0] + offset) << shift;
loads[1] = (avenrun[1] + offset) << shift;
loads[2] = (avenrun[2] + offset) << shift;
}
 
static unsigned long
calc_load(unsigned long load, unsigned long exp, unsigned long active)
{
load *= exp;
load += active * (FIXED_1 - exp);
return load >> FSHIFT;
}
 
/*
 * calc_load - update the avenrun load estimates 10 ticks after the
 * CPUs have updated calc_load_tasks.
 */
void calc_global_load(void)
{
unsigned long upd = calc_load_update + 10;
long active;
 
if (time_before(jiffies, upd))
return;
 
active = atomic_long_read(&calc_load_tasks);
active = active > 0 ? active * FIXED_1 : 0;
 
avenrun[0] = calc_load(avenrun[0], EXP_1, active);
avenrun[1] = calc_load(avenrun[1], EXP_5, active);
avenrun[2] = calc_load(avenrun[2], EXP_15, active);
 
calc_load_update += LOAD_FREQ;
}
 
/*
 * Either called from update_cpu_load() or from a cpu going idle
 */
static void calc_load_account_active(struct rq *this_rq)
{
long nr_active, delta;
 
nr_active = this_rq->nr_running;  //记录在cpu上运行的进程数
nr_active += (long) this_rq->nr_uninterruptible;  //记录不可中断的进程数
 
if (nr_active != this_rq->calc_load_active) {
delta = nr_active - this_rq->calc_load_active;
this_rq->calc_load_active = nr_active;
atomic_long_add(delta, &calc_load_tasks);
}
}
View Code

 

   从上面的代码特别是注释的两行可以看出,Linux记录cpu负载的时候是将cpu队列中的运行进程数和不可中断进程数都统计在内的,这样在对cpu负载分析的时候就需要考虑不可中断的进程的情况
 
 
2.影响cpu负载的进程
  从定义可以看出cpu的负载主要来自在cpu运行的进程数,队列中准备就绪的进程数和不可中断进程数。那么当cpu负载过高的时候如果能够知道当前运行的进程的状态那么就能够判断是哪些进程的运行导致了问题。刚好,在Linux中ps可以帮助查找当前在运行的进程的状态,通过对这些进程的状态的了解,就能够很好的查找问题的真正原因。
  
ps aux可以显示进程的运行状态
  USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND

 

  当使用ps aux后就可以得知一个进程的11项参数,其中STAT是显示进程的运行状态。
  进程的状态有以下几种。
  
=================进程STAT状态==================== 
  D 无法中断的休眠状态(通常 IO 的进程)
  R 正在运行,在可中断队列中; 
  S 处于休眠状态,静止状态; 
  T 停止或被追踪,暂停执行; 
  W 进入内存交换(从内核2.6开始无效); 
  X 死掉的进程; 
  Z 僵尸进程不存在但暂时无法消除;
  W: 没有足够的记忆体分页可分配
  WCHAN 正在等待的进程资源;
 
  <:高优先级进程
  N: 低优先序进程
  L: 有记忆体分页分配并锁在记忆体内 (即时系统或捱A I/O),即,有些页被锁进内存
  s 进程的领导者(在它之下有子进程);
  l 多进程的(使用 CLONE_THREAD, 类似 NPTL pthreads);
  + 位于后台的进程组;

 

 
3.防止cpu负载过高的方法
  短期来看,可以通过kill和killall来杀死一些影响cpu负载的进程,达到降低cpu负载的目的。
  这些进程的状态是可以利用ps 显示出来的,然后对相关的进程采取一定的措施就能在短时间内降低cpu的负载。
  关于kill和killall的用法,这里不做详细的介绍。
 
4.cpu负载过高的进一步分析
  长远来看,要想cpu的负载不高,就要从cpu的利用率和当前的服务来进行分析。
  下面以具体的案例进行分析:
  我们有台服务器,当服务器的链接数过高时,就会导致nfs阻塞(该台服务器和另外一台服务采用nfs共享文件),这时wa为95.8%,负载马上就上升到180.
 
server1:~$ est
    467 connections established
当服务器有大量的链接数时会发生nfs阻塞的问题:
root      2631  0.2  0.0      0     0 ?        D    Jul20  50:28 [nfsd]
root      2632  0.2  0.0      0     0 ?        D    Jul20  49:24 [nfsd]
root      2633  0.2  0.0      0     0 ?        S    Jul20  49:27 [nfsd]
root      2634  0.2  0.0      0     0 ?        S    Jul20  49:47 [nfsd]
root      2635  0.2  0.0      0     0 ?        S    Jul20  51:12 [nfsd]
root      2636  0.2  0.0      0     0 ?        S    Jul20  49:00 [nfsd]
root      2637  0.2  0.0      0     0 ?        S    Jul20  49:39 [nfsd]
root      2638  0.2  0.0      0     0 ?        D    Jul20  50:24 [nfsd]

 

 
server1:~$ top
 
top - 16:13:12 up 14 days, 21:21,  2 users,  load average: 180.20, 59.85, 22.61
Tasks: 125 total,   1 running, 124 sleeping,   0 stopped,   0 zombie
Cpu :  2.3%us,  1.3%sy,  0.0%ni,  0.0%id, 95.8%wa,  0.0%hi,  0.5%si,  0.0%st
Mem:   2076212k total,  2028752k used,    47460k free,     1804k buffers
Swap:  2104472k total,  1089140k used,  1015332k free,   244076k cached

  

通过这种简单的分析,就基本上可以断定问题处在nfs处,需要调整文件共享的方式。
 
5.关于cpu负载和利用率的关系
大家可以参考这里的一篇文章写得很好。

以上是关于cpu负载的探讨的主要内容,如果未能解决你的问题,请参考以下文章

分享几个实用的代码片段(附代码例子)

分享几个实用的代码片段(附代码例子)

测量代码段的 Java 执行时间、内存使用和 CPU 负载

gcc/C++:如果 CPU 负载低,那么代码优化就没啥用了,对吗?

微信聊天的长连设计探讨之负载均衡

一致性哈希负载均衡算法的探讨