1. 程式人生 > 程式設計 >解決多執行緒效能問題技巧分享

解決多執行緒效能問題技巧分享

@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執行緒-同步日誌-執行緒不睡眠

31執行緒-同步日誌-執行緒不睡眠

vmstat(監控虛擬記憶體、程式、IO讀寫、CPU活動)

  • Procs(程式) r: 執行佇列中程式數量,這個值也可以判斷是否需要增加CPU。(長期大於1) b: 等待IO的程式數量。
  • IO(現在的Linux版本塊的大小為1kb) bi: 每秒讀取的塊數 bo: 每秒寫入的塊數 注意:隨機磁碟讀寫的時候,這2個值越大(如超出1024k),能看到CPU在IO等待的值也會越大。

31執行緒-同步日誌-執行緒不睡眠

在這裡插入圖片描述

jstack(jstack是java虛擬機器器自帶的一種堆疊跟蹤工具)

  1. 使用top 定位到佔用CPU高的程式PID top 通過ps aux | grep PID命令
  2. 獲取執行緒資訊,並找到佔用CPU高的執行緒 ps -mp pid -o THREAD,tid,time | sort -rn
  3. 將需要的執行緒ID轉換為16進位制格式 printf "%x\n" tid
  4. 列印執行緒的堆疊資訊 jstack pid |grep tid -A 30
  1. 第一步查程式內執行緒
    在這裡插入圖片描述
  2. 第二部執行緒id轉換
    在這裡插入圖片描述
  3. 分析堆疊
    在這裡插入圖片描述
    在這裡插入圖片描述

總結

如何應對線上故障

  • 淡定
  • 第一時間保障業務正常運轉,根據實際業務情況分析是臨時解決bug或者版本回退
  • 對複雜故障難以定位時,儲存系統日誌必要情況做系統dump,方便後續問題分析
  • 線下分析故障並解決

個人經驗

效能問題分析應該從四個維度:

  • cpu
  • 記憶體(快取)
  • io
  • 網路
  • a.合理的執行緒管理,提升執行緒的執行效率,避免執行緒空轉或發生死鎖。
    b.記憶體資源的合理分配,防止記憶體洩露和記憶體溢位。      
    c.向連線池獲取連線使用完成後,及時close。
    d.外部介面呼叫超時合理設定,防止介面呼叫超時主執行緒夯死。複製程式碼