現(xiàn)象:
通過監(jiān)控工具巡檢自己的服務(wù)發(fā)現(xiàn)服務(wù)cpu load存在周期性變高的現(xiàn)象悠垛,如圖:
機器的cpu核數(shù)是4核川队,最高點明顯超過了4呼奢,但是cpu使用率沒有明顯變高酷勺,如圖:
cpu有突刺的現(xiàn)象是gc時引起的,這里先不做贅述固该;
提出問題
那么是什么原因引起的cpu load變高呢锅减??蹬音?上煤,又該如何解決呢?
查找問題
一著淆、引起load變高的原因有哪些:
1.磁盤io繁忙劫狠,網(wǎng)絡(luò)io繁忙
2.線程上下文切換頻繁
3.cpu繁忙
二、根據(jù)上面提出的三個原因去尋找解決方案
1.io繁忙永部?
由上面三張圖對比可以看出負(fù)載升高的時候独泞,磁盤io以及網(wǎng)絡(luò)io并沒有任何變化還是保持和之前一樣,說明不是io影響的苔埋。
2.線程上下文切換頻繁懦砂?
使用命令:pidstat -w -p <pid>
由以圖可以看出來,每秒自愿上下文切換(voluntary context switches)的次數(shù)為0(cswch )组橄;
被系統(tǒng)強制調(diào)度導(dǎo)致荞膘,每秒非自愿上下文切換(non voluntary context switches)的次數(shù)(nvcswch)的次數(shù)也為0;
說明不是線程頻繁切換導(dǎo)致的
3.cpu繁忙導(dǎo)致玉工?羽资?
從最上面的cpu整體使用率看到并不是很高,那么應(yīng)該不是cpu繁忙導(dǎo)致的遵班;
繼續(xù)向下排查屠升,
pidstat查看java線程內(nèi)詳細信息,可發(fā)現(xiàn)用戶態(tài)cpu使用率很高狭郑,長時間占用CPU腹暖,導(dǎo)致等待線程增多;
結(jié)合服務(wù)業(yè)務(wù)發(fā)現(xiàn):
該服務(wù)是批量拉去kafka消息翰萨,然后使用線程池進行消費脏答,而這個線程池使用的拒絕策略為CallerRunsPolicy,也就是當(dāng)線程池執(zhí)行不過來缨历,并且阻塞隊列也滿的時候就會默認(rèn)使用主線程來進行處理以蕴;
繼續(xù)排查確認(rèn):
1.通過命令top -Hp pid 查看進程下最耗費cpu的線程
2.printf “%x\n” 得到線程的16進制
3.jstack 進程 |grep 線程id 獲取線程狀態(tài)
執(zhí)行以上步驟的到文件,觀察發(fā)現(xiàn)辛孵,最繁忙的線程就是kafka線程
當(dāng)線程池滿了以后丛肮,會默認(rèn)使用kafka的主線程去進行業(yè)務(wù)處理,以上也驗證了這一點魄缚;
解決法案
1宝与、減少一批消息的拉去數(shù)量焚廊,使當(dāng)前線程池足夠消費;
2习劫、增大線程池數(shù)量的核心線程數(shù)(這種需要判斷當(dāng)前服務(wù)是io密集型還是cpu密集型咆瘟,此方案選用)
3、更改業(yè)務(wù)邏輯诽里,減少rpc袒餐,盡量減少業(yè)務(wù)處理,加快消費速度谤狡;
以上三種方式可以一起使用灸眼,也可以部分使用;
實踐方案
1.先減少批量拉取的消息數(shù)墓懂,觀察load是否有降低焰宣;
2.因為我的業(yè)務(wù)服務(wù)是網(wǎng)絡(luò)io密集型,所以我適當(dāng)增大了業(yè)務(wù)線程池的核心線程數(shù)捕仔;
3.最后再來看業(yè)務(wù)邏輯層面是否存在優(yōu)化的空間匕积;
前兩步結(jié)束后,負(fù)載已經(jīng)降低到正常范圍時榜跌,最后一步業(yè)務(wù)邏輯優(yōu)化可選擇性的去做闪唆;