并且這種峰刺出現的頻率不固定,檢視 cat 發現,每小時出現的頻率也固定,多的時候十幾次,少的時候一兩次。有告警資訊可知,是 cat 采集到的 system.process:cpu.system.load.percent 名額超過 60% 導緻。而這個名額一看就是系統 CPU 負載的名額。為了解決這個問題,首先要搞清楚,CPU 負載也就是 CPU Load 是個啥?,是以就有了這篇文章。
可能很多人都看到過一個線程數設定的理論:
CPU 密集型的程式 - 核心數 + 1
I/O 密集型的程式 - 核心數 * 2
這個理論看起來很合理,但實際操作起來,總是不僅如此人意。
下面,我們就來看一下 線程數, CPU 的關系先說一個基本的理論,大家應該都知道:
一個CPU核心,機關時間内隻能執行一個線程的指令
那麼理論上,我一個線程隻需要不停的執行指令,就可以跑滿一個核心的使用率。
下面我們用一段程式來測試下 CPU 和線程數 之間的關系。
CPU 使用率測試
測試環境:公司配置的 mac 電腦(配置太低,日常開發夾到懷疑人生)
2.3 GHz 雙核Intel Core i5,(2 Core, 4 Threads)
8 GB 2133 MHz LPDDR3
來寫個死循環空跑的例子驗證一下:
public static void main(String[] args) {
testWithCalc();
}
public static void testWithCalc() {
while (true) {
}
}
運作這個例子之前,先來來看看現在CPU的使用率:
由 CPU Load 過高告警引發的對 線程數和 CPU 的思考
未運作之前
> 由于本身 有一些程式在跑可以看到,左上角 4 個 CPU 核心數(2核4線程,姑且認為 4個CPU核心),CPU 使用率都是個位數,看起來毫無壓力。右上角 有個 Load average 表示 CPU 的負載,代表 CPU 的處理線程的繁忙程度。
接下來,運作上面的程式之後,再來看看 CPU 的使用率:
由 CPU Load 過高告警引發的對 線程數和 CPU 的思考
1 個線程
從圖上可以看到,我的2号核心使用率達到 50% 多,但是為啥沒有跑滿呢,因為 CPU 執行線程是靠配置設定給線程時間片來運作不同的線程的,而我們的線程是個 while true 會一直循環 CPU ,是以 CPU 的使用率應該是 100 %沒錯,但是對于多核應該是多核的 CPU 使用率加起來,即
0号(28.9%)+1号(18.7)+2号(50.7%)+3号(7.9%) > 100%
那基于上面的理論,我多開幾個線程試試呢?
public static void main(String[] args) {
testWithThreadCalc(2);
}
public static void testWithThreadCalc(int threadNum) {
System.out.println("start ...");
for (int i = 0; i < threadNum; i++) {
new Thread(() -> {
// 模拟計算操作
while (true) {
}
}).start();
}
}
我們先開兩個線程,此時再看CPU使用率:
由 CPU Load 過高告警引發的對 線程數和 CPU 的思考
2 個線程
2 個線程運作我們的程式, 那麼 整體 CPU 使用率 定會大于 200% ,即
0号(68.4%)+1号(35.8)+2号(68.0%)+3号(37.6%) > 200%
那如果開4個線程呢,是不是會把所有核心的使用率都跑滿?答案一定是會的:
public static void main(String[] args) {
testWithThreadCalc(4);
}
public static void testWithThreadCalc(int threadNum) {
System.out.println("start ...");
for (int i = 0; i < threadNum; i++) {
new Thread(() -> {
// 模拟計算操作
while (true) {
}
}).start();
}
}
由 CPU Load 過高告警引發的對 線程數和 CPU 的思考
4 個線程
此時的結果不出我們所料,所有的 CPU 使用率依然達到 100%,而 右上角的 Load average 我們可以看到,才 10% 左右,說明, CPU 負載不是很高,如果這時再增加線程, CPU 排程就會開始繁忙起來,那麼 CPU Load 也會增加,為了印證我們的猜想,把線程數調整到 100 試試(此時的我已帶上頭盔,因為怕這破電腦炸了。。。)。
public static void main(String[] args) {
testWithThreadCalc(100);
}
public static void testWithThreadCalc(int threadNum) {
System.out.println("start ...");
for (int i = 0; i < threadNum; i++) {
new Thread(() -> {
// 模拟計算操作
while (true) {
}
}).start();
}
}
由 CPU Load 過高告警引發的對 線程數和 CPU 的思考
100 個線程(此刻,電腦 CPU 風扇狂轉)
随着風扇的嗡嗡聲,可以看到,我的 4個CPU 還是 100% 的使用率,不過此時的 CPU 負載 Load average 也從 10% 升高到了 98.98%,說明此時CPU更繁忙,線程的任務無法及時執行。很明顯,此刻,我的電腦已不堪重負。