解決多執行緒效能問題技巧分享
阿新 • • 發佈:2019-12-31
@TOC 最近工作中在使用多執行緒處理業務邏輯時遇到了問題,程式執行期初,與之前未使用多執行緒沒有任何差別,但是當對應的執行緒處理佇列開始擁堵時,處理速度開始愈來愈慢,為解決該效能問題,投入多日並作出如下總結
問題定位
業務方法耗時跟蹤
判定原因:某方法耗時較長,拖垮整個業務流程,導致效能下降 驗證過程:在整個業務流程的主方法中加入方法耗時日誌,發現所有方法耗時整體偏慢,且耗時頗長的方法並不唯一,存在隨機性(正常方法耗時在3ms左右,異常時方法耗時平均90ms,更有甚者耗時上百上千毫秒)
同步日誌輸出
判定原因:同步日誌輸出拖慢系統整體效能 驗證過程:針對日誌輸出方式,分別對同步和非同步日誌進行兩次壓測,但是效果雖有改善但是整體影響不大,整體還是偏慢,該原因並不是導致系統問題的主要原因,壓測資料如下
日誌輸出方式 | 速率(5min) | 速率(10min) | 速率(15min) | 速率(20min) | 速率(25min) | 速率(30min) |
---|---|---|---|---|---|---|
同步 | 34972 | 9628 | 11485 | 15927 | 1758 | ~ |
非同步 | 45595 | 48460 | 28836 | 9930 | 1746 |
執行緒數量過多
判定原因:改造後,業務邏輯處理多了31個執行緒,懷疑執行緒數量過多,導致執行緒之間切換時間大於執行緒工作時間 驗證方式:減少啟動執行緒數,啟動16個執行緒進行壓測,結果速率恢復正常,但是通過對系統監控,31個執行緒對於系統整體200多原有執行緒數來說並不算多,執行緒數過多是原因之一但不是主要原因
執行緒空跑
判定原因:31個執行緒在分別處理31個佇列,並不是每個佇列都有值,但是31個執行緒需要常駐,並時刻判斷佇列是否有值,此時空值佇列的消費執行緒無限空轉判斷,造成CPU祕籍,嚴重影響效能 驗證方式:重新啟動31個執行緒,在消費時佇列為空,執行緒強制睡眠5S,結果效果顯著,速率恢復正常,壓測結果如下
執行緒休眠對照 | 日誌輸出方式 | 速率(5min) | 速率(10min) | 速率(15min) | 速率(20min) | 速率(25min) | 速率(30min) |
---|---|---|---|---|---|---|---|
不睡眠 | 同步 | 34972 | 9628 | 11485 | 15927 | 1758 | ~ |
不睡眠 | 非同步 | 45595 | 48460 | 28836 | 9930 | 1746 | |
睡眠 | 同步 | 45716 | 46013 | 46521 | 43581 | 47421 | 45658 |
睡眠 | 非同步 | 43655 | 49189 | 45319 | 47910 | 47761 |
結論:空跑執行緒會嚴重影響系統效能,針對於系統常駐執行緒,在不做業務處理時,需要讓對應執行緒先休息,釋放響應系統資源
複製程式碼
效能分析工具
top(動態檢視程式變化,監控linux的系統狀況)
- Cpu(s): us 使用者空間佔用CPU百分比 sy 核心空間佔用CPU百分比 ni 使用者程式空間內改變過優先順序的程式佔用CPU百分比 id 空閒CPU百分比 wa 等待輸入輸出的CPU時間百分比 hi 硬中斷(Hardware IRQ)佔用CPU的百分比 si 軟中斷(Software Interrupts)佔用CPU的百分比 st (Steal time) 是當 hypervisor 服務另一個虛擬處理器的時候,虛擬 CPU 等待實際 CPU 的時間的百分比。
- Mem: total 實體記憶體總量 used 使用的實體記憶體總量 free 空閒記憶體總量 buffers 用作核心快取的記憶體量 Mem: total 實體記憶體總量 used 使用的實體記憶體總量 free 空閒記憶體總量 buffers 用作核心快取的記憶體量 Swap total 交換區總量 used 使用的交換區總量 free 空閒交換區總量 cached 緩衝的交換區總量。 記憶體中的內容被換出到交換區,而後又被換入到記憶體,但使用過的交換區尚未被覆蓋, 該數值即為這些內容已存在於記憶體中的交換區的大小。 相應的記憶體再次被換出時可不必再對交換區寫入。
31執行緒-同步日誌-執行緒不睡眠
vmstat(監控虛擬記憶體、程式、IO讀寫、CPU活動)
- Procs(程式) r: 執行佇列中程式數量,這個值也可以判斷是否需要增加CPU。(長期大於1) b: 等待IO的程式數量。
- IO(現在的Linux版本塊的大小為1kb) bi: 每秒讀取的塊數 bo: 每秒寫入的塊數 注意:隨機磁碟讀寫的時候,這2個值越大(如超出1024k),能看到CPU在IO等待的值也會越大。
31執行緒-同步日誌-執行緒不睡眠
jstack(jstack是java虛擬機器器自帶的一種堆疊跟蹤工具)
- 使用top 定位到佔用CPU高的程式PID top 通過ps aux | grep PID命令
- 獲取執行緒資訊,並找到佔用CPU高的執行緒 ps -mp pid -o THREAD,tid,time | sort -rn
- 將需要的執行緒ID轉換為16進位制格式 printf "%x\n" tid
- 列印執行緒的堆疊資訊 jstack pid |grep tid -A 30
- 第一步查程式內執行緒
- 第二部執行緒id轉換
- 分析堆疊
總結
如何應對線上故障
- 淡定
- 第一時間保障業務正常運轉,根據實際業務情況分析是臨時解決bug或者版本回退
- 對複雜故障難以定位時,儲存系統日誌必要情況做系統dump,方便後續問題分析
- 線下分析故障並解決
個人經驗
效能問題分析應該從四個維度:
- cpu
- 記憶體(快取)
- io
- 網路
-
a.合理的執行緒管理,提升執行緒的執行效率,避免執行緒空轉或發生死鎖。 b.記憶體資源的合理分配,防止記憶體洩露和記憶體溢位。 c.向連線池獲取連線使用完成後,及時close。 d.外部介面呼叫超時合理設定,防止介面呼叫超時主執行緒夯死。複製程式碼