秒殺場景實踐之搶紅包經常使用解決方案面試
秒殺場景在生活中幾乎隨處可見, 不管是商品搶購、春運搶票仍是一個隨處可見的紅包, 都會涉及到秒殺的場景. 在面試中, 秒殺業務的設計也成爲熱門題目爲面試官和應聘者津津樂道.sql
接下來, 本文將針對秒殺場景中的搶紅包實現方案進行分享, 包括紅包業務常見的實現方案, 瓶頸及優化.數據庫
紅包的應用場景有不少, 如隨機紅包、定額紅包等, 甚至還有結合其餘促銷業務的紅包變種如搶購物津貼等. 但從技術的角度來看, 不論玩法有多少變化, 其核心都是類似的:緩存
搶紅包可能會因爲業務需求不一樣而產生不少變種, 設計上要足夠抽象, 不能爲了搶現金紅包和搶購物津貼紅包寫多份類似的代碼. 搶到紅包的後置操做能夠做爲消息, 由不一樣的業務模塊自行處理.併發
搶紅包核心業務不復雜, 其關鍵點在於應對高併發、資源爭用等.負載均衡
高併發: 異步、橫向擴展負載均衡、限流等.異步
讀多寫少: 緩存.高併發
資源爭用: 原子操做, 緩存或數據庫等層面可進行控制. 如使用Lua腳本進行減庫存操做.post
紅包數量相對合理, 很少產生庫存剩餘的狀況、用戶量級不大的狀況.
預分配是在發放紅包時, 根據紅包總額和數量、按照既定算法進行分配, 提早建立好所有的紅包分配記錄. 領取時只是將紅包分配記錄進行更新.
比較適合系統發放的紅包(面向某一標籤的所有用戶羣體, 發出的紅包基本會被領取完), 不適合用戶羣組紅包(沒法控制領取紅包人數, 當紅包個數遠大於羣組人數的狀況下, 無效數據比較多, 好比在一個10人羣組發放一個數量爲1000的紅包).
在紅包開搶前, 預先分配好紅包領取記錄, 領取記錄的用戶ID爲負值.
開搶後, 開放惟一領取紅包的入口
領取操做核心就是更新紅包分配記錄:
-- 此處劃重點 ( ̄▽ ̄)"
UPDATE IGNORE record SET user_id = {userId}, gmt_receive = UNIX_TIMESTAMP() WHERE red_envelop_id = 1 AND user_id < 0 LIMIT 1;
-- red_envelop_id + user_id 有惟一約束
複製代碼
紅包發放記錄
ID | 總金額 | 數量 | ... |
---|---|---|---|
1 | 100 | 3 | ... |
紅包分配記錄
unique:
紅包ID
+領取用戶ID
ID | 紅包ID | 金額 | 領取用戶ID | 領取時間 | ... |
---|---|---|---|---|---|
1 | 1 | 10 | -1 | 0 | ... |
2 | 1 | 60 | -2 | 0 | ... |
3 | 1 | 30 | -3 | 0 | ... |
UPDATE IGNORE ... LIMIT 1
: 解決了資源爭用問題, 確保併發請求下紅包的領取的數據正確性.red_envelop_id
+ user_id
: 建立索引並惟一約束, 確保對於同一個紅包同一用戶只能領取一次.user_id
爲負值: 由於red_envelop_id
+ user_id
有惟一約束.領取人數沒法估計、頻發退款, 如羣組紅包(常常發生剩餘退款)
紅包發放記錄
ID | 總金額 | 數量 | 剩餘金額 | 剩餘數量 | ... |
---|---|---|---|---|---|
1 | 100 | 3 | 100 | 3 | ... |
紅包分配記錄
unique:
紅包ID
+領取用戶ID
ID | 紅包ID | 金額 | 領取用戶ID | 領取時間 | ... |
---|---|---|---|---|---|
... | ... | ... | ... | ... |
客戶端點擊頻率控制能在必定程度上減小流量.
紅包領光後在緩存一層攔截掉所有請求, 直接返回失敗.
網關層進行限流.
秒殺場景其特色是高併發、讀多寫少、資源爭用, 每個點都須要根據其業務場景選擇適合的解決方案, 如使用緩存解決頻繁讀取的問題、使用隊列解決數據庫性能瓶頸等.
對於搶紅包業務來講, 預分配和實時分配都是行之有效的方案, 各有優劣, 具體選擇哪一種, 仍是要看業務需求.
若是這篇文章對您有幫助,請點個贊吧 ( ̄▽ ̄)"
歡迎關注公衆號(代碼如詩):