1. 程式人生 > >分散式秒殺系統-REDIS(高併發、高效能、庫存資料一致、不限語言-設計思路一致)

分散式秒殺系統-REDIS(高併發、高效能、庫存資料一致、不限語言-設計思路一致)

一、秒殺系統準備

1、首先需要能夠抗住基本請求流量的伺服器環境

2、高可用的redis環境(叢集、主從、資料持久化) ps:如果你的每秒請求只有幾百幾千一個REDIS完全夠用不需要額外操心,另外秒殺功能產品往往會加一個小梗,那就是開始秒殺時使用者需要填寫兌換的賬號才能發起秒殺,這裡根據使用者的操作時間本質上又做了一次/n的分流。其次前端本身還會驗證使用者是否有資格參與秒殺(餘額預驗證)。所以也就是說一場活動可能有10萬人參與,但是有資格的可能只有1萬人,再加操作時間線控制,真實併發最多幾千。一臺NGINX,一臺REDIS完全夠了。

PS:經過測試多節點高併發壓力測試

       除能夠搶到的使用者(會真實落庫),其他被拒絕的使用者:tomcat介面請求響應速度和正常的一個無任何邏輯的介面響應時間誤差1毫秒左右,比如你一個API沒有任何處理:邏輯框架的響應時間為7~8毫秒。那麼秒殺介面響應大約在7~9毫秒

       redis CPU負載基本忽略不計

所以最終的負載消耗,請以自己的伺服器架構配置為準即可。也就是說 本方案僅需要去關注伺服器環境的壓力支撐,不需要刻意關注系統。(redis如果達到瓶頸,首先很難很難,理論上幾十萬人都難以突破,那麼可以一個商品ID走一個reids即可)

3、寫程式碼的碼農

二、程式碼結構

1、redisKey準備【時間複雜度均為O(1)】

  (1:秒殺使用者操作鎖 (參考:http://redisdoc.com/string/set.html 末尾)

        命令:SET resource-name anystring NX EX max-lock-time    

        解鎖:if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end

        key:  FLASH_LOCK  

        內容:{userId}

 (2:秒殺庫存(參考:http://redisdoc.com/string/incr.html)

         命令:incr \ INCRBY

         key: FLASH_COUNT 

         內容:{日期_場次_商品ID}

2、API-秒殺資料查詢介面

獲取配置:場次、開始時間點、結束時間點、商品list{id,name,資格(如積分),總庫存} ,

       注意:如果沒有配置中心或者動態配置需要放在資料庫的話,禁止每次走DB查詢,善用快取

配置計算:計算當前場次,返回商品列表,返回商品剩餘庫存(總庫存-FLASH_COUNT )

額外優化:

      (1、本介面可加入應用記憶體快取模式,場次開始前1分鐘走記憶體,即將開始才走實時REDIS查詢剩餘庫存

      (2、也可以走預生成配置模式,將計算好的邏輯放到REDIS中,介面僅僅做實時庫存查詢

3、API-秒殺介面

(1、使用者授權、基本引數驗證(一般在框架中)

(2、本場本商品ID是否已經沒有了庫存(單商品應用記憶體鎖定,立即減少redis get壓力)【沒有庫存立即響應結果】

(3、獲取使用者操作鎖FLASH_LOCK  【失敗立即響應,操作進行中】

       getLock -》try {程式碼}catch (XX) {日誌}finally {解鎖}

(4、場次開始、商品有效等基本判定【失敗立即響應】

 (5、立即redis get FLASH_COUNT 驗證商品是否有庫存【沒有庫存立即響應結果,寫入單商品應用記憶體鎖定

 (6、驗證使用者資格(如積分是否充足)【沒有餘額立即響應結果】

(7、開始秒殺 incr FLASH_COUNT 【驗證獲取到的序列是否超過庫存,步驟5微秒級同時get到會進入7被最終攔截,如果超過則響應沒有庫存了,寫入單商品應用記憶體鎖定

(8、最終的幸運兒下單、落庫、走各自的獎勵發放流程(可同步可非同步)