CPU的使用率和負載的區別

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 負載和使用率

  1. 高cpu使用率時,負載不一定很高
    一個機器48個核如果全100%的使用率,那麼整個機器使用率是100%,但是負載也可能只是48剛好滿負載而已。

  2. 高負載的時候,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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章