Java 秒殺高併發系統的一些想法設計

最近因爲業務需要,在設計一些秒殺的應用場景,根據網上已經有資料,經過自己綜合分析,得出以下結論,還請多多賜教!!

高併發
一、前端
1,儘可能在上游攔截和限制請求,限制流入後端的量,保證後端系統正常。
因爲無論多少人蔘與秒殺,實際成交往往是有限的,而且遠小於參加秒殺的人數,因此可以通過前端系統進行攔截,限制最終流入系統的請求數量,來保證系統正常進行。
2,靜態化頁面,將頁面緩存在用戶的瀏覽器和CDN上
3,提交後按鈕disabled,禁止用戶重複提交

二、服務器集羣
1.通過nginx分發請求,提前預判會產生的PV數,部署合適數量的服務器集羣,防止其中一臺Web機器掛了,導致流量分散到其他正常工作的機器上,再導致正常的機器也掛,將整個Web系統拖垮
2.優化服務器中間件如tomcat jvm優化(虛擬機初始化時的最小內存,可用最大內存,GC模式等),併發連接優化(初始化 socket線程數,最大socket線程數等)

三、服務端層
1.秒殺業務是一個讀多寫少的場景,大部分請求是查詢請求,多使用緩存對應讀的請求,增加服務端響應速度,減少CPU處理多個連接數的壓力 導致整體響應速度變慢,以及web服務器鏈接數被佔滿

減庫存實現邏輯
2-1.將商品的開始時間放置在redis緩存中,判斷是否到了秒殺開始時間
2-2.請求間隔是否符合正常時間(如將用戶上一次的請求時間記錄下來計算時間差)
2-3.將商品庫存剩餘數量放置到redis緩存中,判斷庫存數量是否還有剩餘
2-4.有剩餘的話,獲取一個redis分佈式鎖
利用redis的.setnx命令,先判斷是否存在再賦值
因爲redis都是串行操作的,不存在併發問題
拿到鎖:
2-5.處理業務邏輯,如將數據放置在一個mq中,然後通過incr、incrby、decr、decrby原子操作命令控制庫存數,減少數據庫IO的開銷
  • incr遞增1並返回遞增後的結果;
  • incrby根據指定值做遞增或遞減操作並返回遞增或遞減後的結果(incrby遞增或遞減取決於傳入值的正負);
  • decr遞減1並返回遞減後的結果;
  • decrby根據指定值做遞增或遞減操作並返回遞增或遞減後的結果(decrby遞增或遞減取決於傳入值的正負);
2-6.釋放鎖,返回應答
未拿到鎖:
2-7.線程sleep再次嘗試拿鎖 ,多次未拿到鎖則返回用戶活動太火爆

3.數據庫層操作sql語句加上樂觀鎖做一個保護


四、防作弊
1.同一個賬號,一次性發出多個請求
部分用戶通過瀏覽器的插件或者其他工具,在秒殺開始的時間裏,以自己的賬號,一次發送上百甚至更多的請求。實際上,這樣的用戶破壞了秒殺和搶購的公平性。
應對方案:
1.同一賬號請求記錄時間戳標記位。(可以在redis里根據用戶ID 記錄一條數據,比如1秒後失效)
2.再次請求的時候判斷標記位是否存在,如果存在就立即打回請求。

2.多個賬號,一次性發送多個請求
例如微博中有轉發抽獎的活動,如果我們使用幾萬個“殭屍號”去混進去轉發,這樣就可以大大提升我們中獎的概率。
如果發現某個IP請求頻率很高
應對方案:
1.返回驗證碼,區分真實用戶

3. 多個賬號,不同IP發送不同請求
黑客操作多個肉雞
應對方案:
1.活動開始前通過一些數據挖掘篩選過濾殭屍號,殭屍賬號也還是有一些共同特徵的,例如賬號很可能屬於同一個號碼段甚至是連號的,活躍度不高,等級低,資料不全等等。根據這些特點,適當設置參與門檻,例如限制參與秒殺的賬號等級。

4. 火車票的搶購
高級的黃牛刷票時,在識別驗證碼的時候使用真實的人,中間搭建一個展示驗證碼圖片的中轉軟件服務,真人瀏覽圖片並填寫下真實驗證碼,返回給中轉軟件。對於這種方式,驗證碼的保護限制作用被廢除了,目前也沒有很好的解決方案。
應對方案:
1.賬號數據進行“數據挖掘”,這些黃牛賬號也是有一些共同特徵的,例如經常搶票和退票,節假日異常活躍等等。將它們分析出來,再做進一步處理和甄別。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章