0x01 CPU使用率
這個比較好理解,先來說說這個概念。使用率其實也就是一段時間內 使用時間/總時間
直接說CPU的使用率計算方式吧:
CPU在t1和t2時間內的使用率=CPU非空閒時間/CPU總時間*100%=(1-CPU的空閒時間/CPU總時間)*100%
很好理解。比如一個單核CPU,你程序寫個死循環,然後很容易把CPU跑到接近100%,因爲死循環不會讓出時間片,就會一直佔用CPU
比如:http://ju.outofmemory.cn/entry/23059
0x02 CPU負載
計算方式
或許你可能已經看了其他的一些博客,裏面多數是cpu load比喻成電話亭打電話、大橋上通車等。這個的確很形象,但是卻並不準確。因爲Linux系統並不是這樣簡單的計算。並不是簡單的平均
CPU Load的計算是使用到了統計學中指數移動平均(英語:exponential moving average,EMA或EXMA)的概念。
爲啥這樣?因爲:
- 移動平均可撫平短期波動,反映出長期趨勢或週期。數學上,移動平均可視爲一種卷積。
- 各數值的加權影響力隨時間而指數式遞減,越近期的數據加權影響力越重,但較舊的數據也給予一定的加權值。
總結一下就是這個統計算法不僅考慮了短期也能反映長期趨勢,不僅計算了近期的值還考慮的舊的數據。
Linux中具體計算方式代碼如下:
calc_load一般是5*Hz就調用一次,(Hz variable is the pulse rate of particular Linux kernel activity,默認值是10ms)
unsigned long avenrun[3];
static inline void calc_load(unsigned long ticks)
{
unsigned long active_tasks; /* fixed-point */
static int count = LOAD_FREQ;
count -= ticks;
if (count < 0) {
count += LOAD_FREQ;
active_tasks = count_active_tasks(); //注意這個函數!!
CALC_LOAD(avenrun[0], EXP_1, active_tasks);
CALC_LOAD(avenrun[1], EXP_5, active_tasks);
CALC_LOAD(avenrun[2], EXP_15, active_tasks);
}
}
真正的計算公式:
#define FSHIFT 11 /* nr of bits of precision */
#define FIXED_1 (1<<FSHIFT) /* 1.0 as fixed-point */
#define LOAD_FREQ (5*HZ) /* 5 sec intervals */
#define EXP_1 1884 /* 1/exp(5sec/1min) as fixed-point */
#define EXP_5 2014 /* 1/exp(5sec/5min) */
#define EXP_15 2037 /* 1/exp(5sec/15min) */
#define CALC_LOAD(load,exp,n) \
load *= exp; \
load += n*(FIXED_1-exp); \
load >>= FSHIFT;
cpu load的確能夠反映出某時間段內活躍進程的量。
函數如下:
/*
* 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);
}
}
上面函數需要注意:
(直接引用參考裏面的話)
- 大多數的Unix系統中的負載只是記錄那些處在運行狀態和可運行狀態的進程,但是Linux有所不同,它會包含那些不可中斷的處於睡眠狀態的進程。這時當這些進程由於I/O的阻塞而不能夠運行,就可能顯著的增加cpu的負載。所以在Unix和Linux下的cpu的負載的計算方法是不一樣的,在設定監測值的時候也需要特別考率。
- Linux記錄cpu負載的時候是將cpu隊列中的運行進程數和不可中斷進程數都統計在內的,這樣在對cpu負載分析的時候就需要考慮不可中斷的進程的情況
所以這個函數纔是重點啊:在分析機器負載過高的時候,除了需要關注那些活躍的進程,還需要關注那些由於I/O的阻塞變成不可中斷狀態的進程。很多時候機器負載突然飆升可能就是IO引起的。
至於load的算法瞭解就行。
另外插入介紹一下上面說的不可中斷進程:
(我覺得這個說的比較好,https://cloud.tencent.com/developer/news/376204)
所謂不可中斷sleep是指不能立刻響應處理一些信號的sleep進程,唯一可以喚醒進程的只能是一些等待的資源變得可用(如I/O)或者是等待的時間超時(如果超時時間在進程被置爲sleep時已經指定)。
不可中斷的sleep通常都由設備驅動程序用來等待磁盤或者網絡I/O。該進程從系統調用或陷阱中返回後會收到在其sleep期間累積的信號。在Linux系統中ps -l指令使用字母D來表示不可中斷sleep的狀態。
這個狀態一般表示進程正在跟硬件交互,並且交互過程不允許被其他進程或中斷打斷。kill -9 也無法殺死
負載值大小
一個CPU滿負載其值應該是1,超過1就是過載,低於1一般也沒啥壓力
n個CPU滿負載其值應該是n,超過n就是過載,低於n一般沒啥壓力
機器過載的話,一般就變得很卡,基本都會影響到上面的服務了,要很重視。
0x03 負載和使用率
-
高cpu使用率時,負載不一定很高
一個機器48個核如果全100%的使用率,那麼整個機器使用率是100%,但是負載也可能只是48剛好滿負載而已。 -
高負載的時候,cpu使用率不一定高
可能由於多個進程運行不可中斷的IO,導致活躍進程數量增加,這個時候負載會飈的很高,但是cpu可能很低
0x04 舉個栗子
(高負載,低IO的)
機器配置是48核的。
下圖是出問題的機器,負載突然變成1000多。嚇死個人,但是CPU就30多
一套軍體拳:iostat, sar, demsg, mpstat, pidstat, free, vmstat
發現磁盤IO最高也就200MB/s,並不高並沒有到瓶頸,網絡IO也不高,機器是萬兆網卡。最後通過vmstat 發現了端倪,見下圖。
r:表示運行和等待CPU時間片的進程數
可以看見已經很高了,爆表了。
而正常的機器上是這個樣的:
後來在出問題的機器上ps -ef一看發現有好幾百個同樣的腳本再跑,而這個腳本里面有這麼一段:
find / -name ""
OK!,問題找到。本來只需要一個這樣的腳本跑。其他的都殺了
可以看見run
參考:
cpu使用率
1 http://www.voidcn.com/article/p-yqnvtups-xu.html
cpu負載
2 https://en.wikipedia.org/wiki/Load_%28computing%29#cite_note-5
3 https://zh.wikipedia.org/wiki/%E7%A7%BB%E5%8B%95%E5%B9%B3%E5%9D%87
4 https://github.com/autowebkit/tech/wiki/CPU%E8%B4%9F%E8%BD%BD
5 http://einverne.github.io/post/2019/03/cpu-load.html
6 https://lotabout.me/2018/how-system-load-is-calculated/
如何處理不可中斷進程
https://www.cnblogs.com/xiaowenshu/p/10477591.html