03.23 JAVA高併發秒殺系統構建之高併發優化分析

JAVA高併發秒殺系統構建之高併發優化分析

前言:本文章是《JAVA高併發秒殺系統構建之——業務分析和Web層》下一篇,主要講解系統高併發優化分析

先來分析一下java 控制事務行為

如下圖可知,java事務是串聯發生的,即當一個事務還沒有執行完,其他事務都是要等待而被阻塞。?

JAVA高併發秒殺系統構建之高併發優化分析

那一個事務具體要幹什麼東西呢?或者說高併發的瓶頸在哪裡,看下圖?

JAVA高併發秒殺系統構建之高併發優化分析

分析:?

1、一個Java事務可能有多條sql語句的操作,此時算上sql語句操作時間。?

2、網絡會出現延遲。?

3、GC(java回收機制)處理時,會消耗一定的時間?

綜上,Java事務處理時間=sql消耗+網絡延遲+GC消耗,一個java事務處理時間大約在2ms,也就是說1秒只能有500個事務串行發生,這是非常不高效的。


而之前說的行級鎖(保證java事務之間可以串行進行,從而保證數據的一致性),則在commit之後就會釋放,所以我們的優化方向,就是減少行級鎖的持有時間

我們先分析如何判斷update語句成功更新?

1、update語句自身沒有報錯?

2、客戶端確認update影響記錄數?

所以我們在這個方面的優化方案時,把客戶端邏輯放到mysql服務端,避免網絡延遲和GC?

即為,使用存儲過程:整個事務在Mysql端進行,因為這樣可以將網絡延遲和GC消耗降至最低,大大減少了整個事務的運行時間,同時,Mysql一秒中可以做出幾萬次的事務,是非常高效快速的。


下面開始秒殺的實際優化

首先優化的應該是秒殺地址暴露接口,這裡說下為啥要優化它?

1.因為秒殺地址暴露接口是根據後臺判斷秒殺開始時間,結束時間,以及當前時間來給客戶端返回秒殺地址的,所以無法放進CDN中。?

2.秒殺地址暴露是在秒殺執行之前需要進行的動作,因此伴有大量的併發操作,同時需要請求數據庫,因此必須要優化。?

3.針對這些情況,我們可以用redis,優化秒殺地址暴露接口。

首先建立一個redisDao類,專門進行與Redis有關的業務邏輯?

JAVA高併發秒殺系統構建之高併發優化分析


這裡需要聲明一下,如果從redis中獲得數據,是獲得byte的數組,而不是具體的類,因為redis無法幫你反序列化,因此,反序列化的操作應該由你自己完成。

因為java內置的序列化接口Serializable,效率沒有protostuff自定義序列化高,protostuff的反序列化效率比Serializable高了很多倍,而且壓縮後的空間比Serializable小了10倍左右,因此,使用protostuff進行自定義反序列化操作。

這裡生成protostuff的一個schem,其原理是將Seckill.class的字符碼傳過去,然後利用反射的原理,獲得Seckill中的屬性值等。?

JAVA高併發秒殺系統構建之高併發優化分析

接下來,通過redis獲得緩存中的Seckill對象,以及一些protostuff的反序列化操作?

JAVA高併發秒殺系統構建之高併發優化分析

JAVA高併發秒殺系統構建之高併發優化分析

接下來是將Seckill對象放進redis緩存中,這裡同樣利用protostuff來序列化Seckill,LinkedfBuffer為緩衝器,保證在大型類序列化時能夠起到緩衝的作用,timeout設置緩存時間,這裡設置一小時之後redis中的Seckill數據就會消失。result為redis返回的結果,可以依據此判斷緩存是否成功。?

JAVA高併發秒殺系統構建之高併發優化分析

這兩個方法寫好後,我們回到SeckillServiceImpl中,將之前Seckill直接從數據庫中獲取的流程,改成先判斷redis裡面有沒有Seckill緩存,如果有,直接從redis中獲取,如果沒有,從數據庫中取出Seckill,將其放入redis中。這裡運用在超時的基礎上維護redis數據的一致性,是最基礎的維護一致性的方式。?

JAVA高併發秒殺系統構建之高併發優化分析

以上就是通過redis來緩存信息,下面我們來看執行秒殺操作時的併發優化

上面我們總結過,行級鎖的主要發生地,主要是庫存update操作這裡,之前的業務邏輯如下圖?

由下圖可知,無論這個商品是否可以被秒殺,都會執行update語句,獲得行級鎖,再返回是否update成功的結果,並通過這個update操作結果,來插入購買明細,這是非常錯誤的。?

我們知道,insert操作也可以判斷是否插入成功(返回值0代表失敗,1代表成功),但是,insert操作是不用通過行級鎖來阻塞其他事務的,因此,我們可以將update語句和insert語句調換位置(先過濾不符合update操作條件的事務,即擋住一部分重複秒殺),通過insert語句的結果,來判斷是否需要update操作,這樣,阻塞時間將會大大減少,增加了系統的性能。?

JAVA高併發秒殺系統構建之高併發優化分析

下圖是調換位置後的事務執行?

JAVA高併發秒殺系統構建之高併發優化分析

下面來看看具體代碼的修改?

JAVA高併發秒殺系統構建之高併發優化分析


接下來是深度優化,即將事務SQL在Mysql端進行(存儲過程),減少網絡延遲和GC帶來的時間消耗

下面將插入購買明細和更新庫存操作,放在存儲過程裡面執行?

JAVA高併發秒殺系統構建之高併發優化分析

JAVA高併發秒殺系統構建之高併發優化分析

這裡簡單說明一下存儲過程:?

1.存儲過程主要優化事務行級鎖持有時間?

2.不要過度依賴存儲過程?

3.簡單的邏輯可以應用存儲過程?

4.一秒可以接受4000個請求,這是基本足夠的。

下面說說在java客戶端是如何調用存儲過程的

在SeckillDao中,使用存儲過程執行秒殺?

JAVA高併發秒殺系統構建之高併發優化分析

然後在seckillDao.xml中實現它?

JAVA高併發秒殺系統構建之高併發優化分析

在SeckillService接口中定義一個方法,作為利用存儲過程來實現事務的方法,其參數和executeSeckill方法一樣?

JAVA高併發秒殺系統構建之高併發優化分析

然後編寫其實現類?

JAVA高併發秒殺系統構建之高併發優化分析

JAVA高併發秒殺系統構建之高併發優化分析

以上,就是高併發優化分析的全部內容了。


分享到:


相關文章: