1. 程式人生 > >秒殺系統性能測試和優化

秒殺系統性能測試和優化

對於大併發量的系統,有幾個可能需要優化的點,下面我們要一步步測試來優化這個系統。

測試目標

對於一個系統,幾個常用的評價指標是:平均響應時間、吞吐率、qps等。我的測試主要測試3個介面

  1. 主頁(訪問根路徑,沒有資料庫互動)
  2. 秒殺介面暴露(暴露秒殺介面,有後臺數據互動)
  3. 執行秒殺操作(插入秒殺成功記錄和減庫存一個完整的事務操作)

對於這三個介面,我們主要的測試目標和優化目標是平均響應時間,當然這是建立在資料正確返回的基礎上的,失敗率太高那這個平均響應時間是沒有意義的。
這裡的優化側重於後端資料庫和記憶體方面的優化。

測試環境

我是在Windows10下用jmeter來進行負載測試和壓力測試,其他環境如下,涉及具體配置再提。

  • Tomcat8.0.38
  • Jdk1.8 hotspot vm
  • Mysql 5.7
  • Redis 2.7.3

測試過程

首先進行主頁測試,我們訪問tomcat的主頁,使用jmeter的執行緒組中的執行緒數模擬使用者數,不斷增加執行緒數對主頁進行效能測試。
我們將結果資料寫到一個xml檔案中。首先我們模擬5000個使用者同時請求主頁。

5000個使用者同時請求主頁

設定迴圈次數為2,即一共有10000個請求將被髮送。

這裡寫圖片描述

從響應的結果可以看到,沒有錯誤數,這10000個請求全部返回成功了,只是有的請求慢有的請求快。平均的響應時間在300ms,50%的請求的響應時間平均為87ms。到後面越來越多的請求開始等待,這裡可以想到的優化的點在於tomcat的執行緒池中執行緒的數量,越來越多的請求在等待佇列中。檢視tomcat的配置後發現最大執行緒數為maxThreads=”150”,好那我們用150個執行緒,迴圈10次,也就是一共1500個請求,那結果會是什麼樣呢?

這裡寫圖片描述

平均相應時間為5ms,前50%的請求的平均響應時間為1ms。
但是這裡並不能直接修改tomcat的最大執行緒數來優化。複雜點說就是這是一個複雜的東西,執行緒數越大,你也要有相應的cpu來執行啊。直接點說就是,我不懂。。。
我把tomcat的執行緒數設定為500,然後起5000個執行緒傳送10000個請求,然後得到了:

這裡寫圖片描述

比之前的更差了。無論是平均相應時間還是錯誤率。簡單粗暴的去改執行緒數是不可行的。這裡我們不去管tomcat的執行緒數或者是其他層面的優化,我們只專注於後端資料庫層面的優化。

500個使用者同時請求暴露秒殺介面

為什麼用500個,是為了減少因為tomcat請求等待帶來的資料誤差。
直接向MySQL請求資料


先模擬500個使用者,每個使用者傳送10次請求。該請求相應的操作為根據id向資料庫查詢一條記錄。得到了這樣的資料。

這裡寫圖片描述

期間開啟windows的效能監控器,發現磁碟IO有變化,IO百分比最高的時候也不超過15%。
這樣的操作,錯誤率為0,相當穩定,平均響應時間為1406ms。
模擬5000個使用者,每個使用者傳送一次請求。、

這裡寫圖片描述

磁碟的IO百分比一度達到了100%。從資料的絕對值來看,這樣的測試沒有意義了,因為瓶頸不在MySQL,而在我們前面分析過的tomcat。但是資料的相對值是有意義的。

使用redis快取資料
還是模擬500個使用者,每個使用者傳送10次請求。

這裡寫圖片描述

響應速度顯著提高,注意一個值,Min=1,有些請求幾乎不足1ms,因為redis直接從記憶體讀取數值,非常快。如果不是tomcat的請求在排隊,我想平均響應時間是個位數。
Redis下模擬5000個使用者,每個使用者傳送一次請求。會是什麼結果呢?

這裡寫圖片描述

使用150個執行緒,迴圈100次,即傳送15000次請求,得到:

這裡寫圖片描述

可以看到,150個使用者的話這種響應速度是可以接受的,響應的瓶頸在於tomcat的請求排隊等待。

———–我是分割線—————-

這個優化的過程我想到了很多東西,感覺就是,優化是無止盡的。
比如,我想到了記憶體回收那一塊。選用合適的垃圾收集器,儘可能地減少GC時stop the world的時間和次數顯然對於一個秒殺系統來說是非常對的優化方向。這裡我嘗試用過幾款垃圾收集器比如parNew,G1來對比他們的平均響應時間,但是多次測試後沒有明顯的差距。有兩個原因,一是這個介面沒有產生太多的大物件,二是這個優化並不太明顯。後面有機會的話還是希望繼續在記憶體方面進行優化,感覺記憶體回收方面有點神祕,很想試一試。

————我是分割線————-

可以看到redis的使用很大程度上提高了響應的時間。上面那個介面只是暴露一個地址,這些地址每個產品都只有一個,那這樣的場景是可以用redis的。但是有些操作並沒有辦法使用快取。比如執行秒殺這個操作。
這個操作是個事務型操作。如果其中一個操作失敗了,我就讓他rollback,這樣的話,應該會有更多的併發問題。
見下篇。