1. 程式人生 > 其它 >效能測試常見問題分析

效能測試常見問題分析

一、記憶體溢位

1、堆記憶體溢位

現象:

  (1)壓測執行一段時間後,系統處理能力下降。這時用JConsole、JVisualVM等工具連上伺服器檢視GC情況,每次GC回收都不徹底並且可用堆記憶體越來越少。

  (2)壓測持續下去,最終在日誌中有報錯資訊:java.lang.OutOfMemoryError.Java heap space。

排查手段:

  (1)使用jmap -histo pid > test.txt命令將堆記憶體使用情況儲存到test.txt檔案中,開啟檔案檢視排在前50的類中有沒有熟悉的或者是公司標註的類名,如果有則高度懷疑記憶體洩漏是這個類導致的。

  (2)如果沒有,則使用命令:jmap -dump:live,format=b,file=test.dump pid生成test.dump檔案,然後使用MAT進行分析。

  (3)如果懷疑是記憶體洩漏,也可以使用JProfiler連上伺服器在開始跑壓測,執行一段時間後點擊“Mark Current Values”,後續的執行就會顯示增量,這時執行一下GC,觀察哪個類沒有徹底回收,基本就可以判斷是這個類導致的記憶體洩漏。

解決方式:優化程式碼,物件使用完畢,需要置成null。

2、永久代 / 方法區溢位

現象:壓測執行一段時間後,日誌中有報錯資訊:java.lang.OutOfMemoryError: PermGen space。

產生原因:由於類、方法描述、欄位描述、常量池、訪問修飾符等一些靜態變數太多,將持久代佔滿導致持久代溢位。

解決方法:修改JVM引數,將XX:MaxPermSize引數調大。儘量減少靜態變數。

3、棧記憶體溢位

現象:壓測執行一段時間後,日誌中有報錯資訊:java.lang.StackOverflowError。

產生原因:執行緒請求的棧深度大於虛擬機器所允許的最大深度,遞迴沒返回,戒者迴圈呼叫造成。

解決方法:修改JVM引數,將Xss引數改大,增加棧記憶體。棧記憶體溢位一定是做批量操作引起的,減少批處理資料量。

4、系統記憶體溢位

現象:壓測執行一段時間後,日誌中有報錯資訊:java.lang.OutOfMemoryError: unable to create new native thread。

產生原因:作業系統沒有足夠的資源來產生返個執行緒造成的。系統建立執行緒時,除了要在Java堆中分配記憶體外,作業系統本身也需要分配資源來建立執行緒。因此,當執行緒數量大到一定程度以後,堆中或許還有空間,但是作業系統分配不出資源來了,就出現這個異常了。

解決方法:

  (1)減少堆記憶體

  (2)減少執行緒數量

  (3)如果執行緒數量不能減少,則減少每個執行緒的堆疊大小,通過-Xss減小單個執行緒大小,以便能生產更多的執行緒。

5、JAVA直接記憶體溢位

現象:壓測執行一段時間後,日誌中有報錯資訊:OutOfMemoryError

產生原因:

  (1)直接記憶體大多時候也被稱為堆外記憶體,直接記憶體通過 native 方法可以分配堆外記憶體,通過 DirectByteBuffer 物件來操作。直接記憶體不屬於 Java 堆,所以它不受堆記憶體大小限制,但是它受實體記憶體大小的限制。

  (2)可以通過 -XX:MaxDirectMemorySize 引數來設定最大可用直接記憶體,如果啟動時未設定則預設為最大堆記憶體大小,即與 -Xmx 相同。即假如最大堆記憶體為1G,則預設直接記憶體也為1G,那麼 JVM 最大需要的記憶體大小為2G多一些。當直接記憶體達到最大限制時就會觸發GC,如果回收失敗則會引起OutOfMemoryError。

  (3)直接記憶體在讀和寫的效能都優於堆內記憶體,但是記憶體申請速度卻不如堆內記憶體。

解決方法:因此直接記憶體適用於需要大記憶體空間且頻繁訪問的場合,不適用於頻繁申請釋放記憶體的場合。在需要頻繁申請的場景下不應該使用直接記憶體(DirectMemory),而應該使用堆內記憶體(HeapMemory)。

二、CPU過高

1、us cpu高

現象:壓測過程中,使用top命令檢視系統資源佔用情況,us cpu過高,超過50%以上。

排查手段:

  (1)使用top命令是哪個程序消耗CPU高

  (2)再找到CPU消耗高的執行緒:top -H -p 程序號

  (3)把執行緒號轉換成16進位制:printf "%x\n" 執行緒號

  (4)再用jstack命令分析這個執行緒是在幹什麼:jstack 程序號 | grep 16進位制的執行緒號

  (5)通過JProfiler的CPU Views檢視的層層分析,可以清楚的找到造成CPU高的原因

2、sy cpu高

現象:壓測過程中,使用top命令檢視系統資源佔用情況,sy cpu過高,超過50%以上。

排查手段:

  (1)首先檢視磁碟繁忙程度、磁碟的佇列(iostat、nmon)

  (2)如果磁碟沒有問題,則使用strace檢視系統核心呼叫情況

三、執行緒死鎖

現象:

  (1)壓測進行一段時間後,程式停頓,報超時錯誤。但這種現象並不一定就是執行緒死鎖造成的,也可能是資料庫/中介軟體連線池被佔滿、資料庫死鎖造成的。

  (2)能夠開啟頁面,但獲取不到資料

排查手段:

  (1)使用jstack命令檢視Java程序下所有執行緒的情況:jstack -l 程序號

  (2)如果有Blocked狀態的執行緒,說明有執行緒死鎖的狀況。如果大量執行緒都是Waiting狀態,則需要去關注資料庫和中介軟體,可能會有排隊情況。

  (3)也可以使用JConsole、JVisualVM及JProfiler等工具直接檢視所有執行緒的情況

四、資料庫連線池不釋放

現象:壓測進行一段時間後,報連線超時的錯誤。

排查手段:

  (1)去資料庫檢視應用程式到資料庫的連線有多少個:show full processlist。加入應用程式中配置的最大連線數為30,而通過命令show full processlist檢視到的從應用伺服器連線過來的連線數也為30,證明資料庫連線池佔滿了。

  (2)將應用程式中的最大連線數改大一點(比如100),再重新進行壓測,如果還是出現連線池被佔滿的情況,則證明是資料庫連線池不釋放造成的.

解決方法:排查程式碼,資料庫連線部分應該是有建立連線但是沒有關閉連線的情況。讓開發修改程式碼即可。

五、資料庫死鎖

現象:

  (1)壓測進行一段時間後,報連線超時的錯誤。

  (2)程式在執行的過程中,點選確定或儲存按鈕,程式沒有響應,也沒有出現報錯。

排查手段:檢視資料庫日誌,看有沒有死鎖的情況:show engine innodb status\G。

六、SQL使用不合理

現象:事物響應時間慢

排查手段:

  (1)開啟資料庫的慢查詢

  (2)通過命令找到執行比較久的SQL語句:mysqldumpslow

  (3)利用explain來優化這條SQL語句

七、TPS上不去

1、網路頻寬

  在壓力測試中,有時候要模擬大量的使用者請求,如果單位時間內傳遞的資料包過大,超過了頻寬的傳輸能力,那麼就會造成網路資源競爭,間接導致服務端接收到的請求數達不到服務端的處理能力上限。

2、連線池

  最大連線數太少,造成請求等待。連線池一般分為伺服器中介軟體連線池(比如Tomcat)和資料庫連線池(或者理解為最大允許連線數也行)。

3、垃圾回收機制

  從常見的應用伺服器來說,比如Tomcat,如果堆記憶體設定比較小,就會造成新生代的Eden區頻繁的進行Young GC,老年代的Full GC也回收較頻繁,那麼對TPS也是有一定影響的,因為垃圾回收時通常會暫停所有執行緒的工作。

4、資料庫

  高併發情況下,如果請求資料需要寫入資料庫,且需要寫入多個表的時候,如果資料庫的最大連線數不夠,或者寫入資料的SQL沒有索引沒有繫結變數,抑或沒有主從分離、讀寫分離等,就會導致資料庫事務處理過慢,影響到TPS。

5、硬體資源

包括CPU(配置、使用率等)、記憶體(佔用率等)、磁碟(I/O、頁交換等)。

6、壓力機

  比如Jmeter和Loadrunner,單機負載能力有限,如果需要模擬的使用者請求數超過其負載極限,也會間接影響TPS(這個時候就需要進行分散式壓測來解決其單機負載的問題)。

7、業務邏輯

業務解耦度較低,較為複雜,整個事務處理線被拉長也會導致TPS上不去。

8、系統架構

比如是否有快取服務,快取伺服器配置,快取命中率、快取穿透以及快取過期等,都會影響到測試結果。

八、500或503錯誤

現象:壓測過程中,伺服器返回500或503錯誤

排查手段

  (1)通過瀏覽器訪問網站,如果瀏覽器打不開,伺服器可能掛了。可能的原因是:記憶體溢位、資料庫連線池滿了、執行緒死鎖。

  (2)先看JVM記憶體是否滿了:jstat -gcutil 2384 1000 5

  (3)看資料庫連線池大小是否佔滿,把最大連線數改大,如果還是出現這種現象,證明是資料庫連線池不釋放。

  (4)最後看是否有執行緒死鎖:jstack -l 程序號

九、效能問題分析流程

  1、檢視伺服器的CPU、記憶體 、負載等情況,包括應用伺服器和資料庫伺服器

  2、檢視資料庫健康狀態,資料庫死鎖、連線池不釋放

  3、檢視專案日誌(檢視無報錯現象)

  4、檢視jvm的gc等情況