摘要:確定cpu的負(fù)載的定義陋桂,幫助管理員設(shè)置cpu負(fù)載閥值哑蔫,推測(cè)可能的導(dǎo)致cpu負(fù)載過(guò)高的原因中狂,進(jìn)而保證服務(wù)器的正常運(yùn)行。
1.cpu負(fù)載的定義
首先晤斩,看看cpu負(fù)載的定義餐弱。在一般情況下可以將單核心cpu的負(fù)載看成是一條單行的橋宴霸,數(shù)字1代表cpu剛好能夠處理過(guò)來(lái),即橋上能夠順利通過(guò)所有的車輛膏蚓,
橋外沒(méi)有等待的車輛瓢谢,橋是暢通的。當(dāng)超過(guò)1時(shí)表示有等待上橋的車輛驮瞧,小于1時(shí)表示車輛能夠快速的通過(guò)氓扛。單核心cpu就表示該cpu能夠處理的事務(wù)數(shù)是1,在多核
cpu中cpu能夠并行處理的事務(wù)的數(shù)量應(yīng)該是cpu個(gè)數(shù)*cpu核數(shù)论笔,而且負(fù)載數(shù)最好不要超過(guò)這個(gè)數(shù)值采郎。例如一個(gè)4核cpu,則cpu_load最大值為4狂魔,不能長(zhǎng)期超過(guò)4尉剩,否則會(huì)有任務(wù)沒(méi)有得到及時(shí)的處理,而使系統(tǒng)的負(fù)載累積增高,導(dǎo)致系統(tǒng)運(yùn)行緩慢毅臊。
大多數(shù)的Unix系統(tǒng)中的負(fù)載只是記錄那些處在運(yùn)行狀態(tài)和可運(yùn)行狀態(tài)的進(jìn)程理茎,但是Linux有所不同黑界,它會(huì)包含那些不可中斷的處于睡眠狀態(tài)的進(jìn)程。這時(shí)當(dāng)這些進(jìn)程由于I/O的阻塞而不能夠運(yùn)行皂林,就可能顯著的增加cpu的負(fù)載朗鸠。所以在Unix和Linux下的cpu的負(fù)載的計(jì)算方法是不一樣的,在設(shè)定監(jiān)測(cè)值的時(shí)候也需要特別考率础倍。
下面從內(nèi)核源碼中分析cpu負(fù)載的計(jì)算根源烛占,這里能夠給出cpu負(fù)載的完整計(jì)算方法。下面的代碼是是在kernel-2.6.32中的kernel/shed.c中截取的沟启,用來(lái)計(jì)算cpu的平均負(fù)載忆家。
/* 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上運(yùn)行的進(jìn)程數(shù)
nr_active += (long) this_rq->nr_uninterruptible; //記錄不可中斷的進(jìn)程數(shù)
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);
}
}
從上面的代碼特別是注釋的兩行可以看出,Linux記錄cpu負(fù)載的時(shí)候是將cpu隊(duì)列中的運(yùn)行進(jìn)程數(shù)和不可中斷進(jìn)程數(shù)都統(tǒng)計(jì)在內(nèi)的德迹,這樣在對(duì)cpu負(fù)載分析的時(shí)候就需要考慮不可中斷的進(jìn)程的情況
2.影響cpu負(fù)載的進(jìn)程
從定義可以看出cpu的負(fù)載主要來(lái)自在cpu運(yùn)行的進(jìn)程數(shù)芽卿,隊(duì)列中準(zhǔn)備就緒的進(jìn)程數(shù)和不可中斷進(jìn)程數(shù)。那么當(dāng)cpu負(fù)載過(guò)高的時(shí)候如果能夠知道當(dāng)前運(yùn)行的進(jìn)程的狀態(tài)那么就能夠判斷是哪些進(jìn)程的運(yùn)行導(dǎo)致了問(wèn)題胳搞。剛好卸例,在Linux中ps可以幫助查找當(dāng)前在運(yùn)行的進(jìn)程的狀態(tài),通過(guò)對(duì)這些進(jìn)程的狀態(tài)的了解肌毅,就能夠很好的查找問(wèn)題的真正原因筷转。
#ps aux可以顯示進(jìn)程的運(yùn)行狀態(tài)
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
當(dāng)使用ps aux后就可以得知一個(gè)進(jìn)程的11項(xiàng)參數(shù),其中STAT是顯示進(jìn)程的運(yùn)行狀態(tài)悬而。
進(jìn)程的狀態(tài)有以下幾種呜舒。
=================進(jìn)程STAT狀態(tài)====================
D 無(wú)法中斷的休眠狀態(tài)(通常 IO 的進(jìn)程)
R 正在運(yùn)行,在可中斷隊(duì)列中笨奠;
S 處于休眠狀態(tài)袭蝗,靜止?fàn)顟B(tài);
T 停止或被追蹤艰躺,暫停執(zhí)行呻袭;
W 進(jìn)入內(nèi)存交換(從內(nèi)核2.6開(kāi)始無(wú)效)眨八;
X 死掉的進(jìn)程腺兴;
Z 僵尸進(jìn)程不存在但暫時(shí)無(wú)法消除;
W: 沒(méi)有足夠的記憶體分頁(yè)可分配
WCHAN 正在等待的進(jìn)程資源廉侧;
<:高優(yōu)先級(jí)進(jìn)程
N: 低優(yōu)先序進(jìn)程
L: 有記憶體分頁(yè)分配并鎖在記憶體內(nèi) (即時(shí)系統(tǒng)或捱A I/O)页响,即,有些頁(yè)被鎖進(jìn)內(nèi)存
s 進(jìn)程的領(lǐng)導(dǎo)者(在它之下有子進(jìn)程);
l 多進(jìn)程的(使用 CLONE_THREAD, 類似 NPTL pthreads)段誊;
+ 位于后臺(tái)的進(jìn)程組闰蚕;
3.防止cpu負(fù)載過(guò)高的方法
短期來(lái)看,可以通過(guò)kill和killall來(lái)殺死一些影響cpu負(fù)載的進(jìn)程连舍,達(dá)到降低cpu負(fù)載的目的没陡。
這些進(jìn)程的狀態(tài)是可以利用ps 顯示出來(lái)的,然后對(duì)相關(guān)的進(jìn)程采取一定的措施就能在短時(shí)間內(nèi)降低cpu的負(fù)載。
關(guān)于kill和killall的用法盼玄,這里不做詳細(xì)的介紹贴彼。
4.cpu負(fù)載過(guò)高的進(jìn)一步分析
長(zhǎng)遠(yuǎn)來(lái)看,要想cpu的負(fù)載不高埃儿,就要從cpu的利用率和當(dāng)前的服務(wù)來(lái)進(jìn)行分析器仗。
下面以具體的案例進(jìn)行分析:
我們有臺(tái)服務(wù)器,當(dāng)服務(wù)器的鏈接數(shù)過(guò)高時(shí)童番,就會(huì)導(dǎo)致nfs阻塞(該臺(tái)服務(wù)器和另外一臺(tái)服務(wù)采用nfs共享文件)精钮,這時(shí)wa為95.8%,負(fù)載馬上就上升到180.
server1:~$ est
467 connections established
當(dāng)服務(wù)器有大量的鏈接數(shù)時(shí)會(huì)發(fā)生nfs阻塞的問(wèn)題:
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]
通過(guò)這種簡(jiǎn)單的分析剃斧,就基本上可以斷定問(wèn)題處在nfs處轨香,需要調(diào)整文件共享的方式。
5.關(guān)于cpu負(fù)載和利用率的關(guān)系
大家可以參考這里的一篇文章寫(xiě)得很好悯衬。
http://www.blogjava.net/cenwenchu/archive/2008/06/30/211712.html