唉?就記得當時搶冰墩墩的時候的秒殺了
我們要注意什么問題呢?
1.幾百萬人在這個瞬間搶冰墩墩?這個瞬間會有大量的請求?服務器要能抗的住
2.不能超賣,就那些冰墩墩?賣多了壓根沒有?好不容易搶到你說沒貨了怕不是要被沖爛
3.避免少賣?攏共就那些?你再少賣點?沒屁了
4.防黃牛?還是那個道理?攏共就五百個?黃牛每人嗯造十個?沒了?
高并發問題
基本解決高并發的方法都是?削峰、限流、異步、補償
異步這一步可以通過消息隊列來實現,將搶和購解耦,還可以很方便地限頻,不至于讓MySQL過度承壓。搶的話使用Redis來做處理,因為Redis處理 簡單的扣減請求是非常快的,而直接到MySQL是比較力不從心。
Redis可是單機支撐每秒幾萬的寫入,并且可以做成集群,提高擴展能力的。我們可以先將庫存名額預加載到Redis,然后在Redis中進行扣減,扣減成功的再通過消息隊列,傳遞到MySQL做真
正的訂單生成。
超賣問題
第一步,判斷庫存名額是否充足;
第二步,減少庫存名額,扣減成功就是搶到。
用LUA把這兩個捆綁成一個原子操作就好
1.正常業務錯誤,比如庫存用完,這種情況符合預期,直接返回給用戶即可。
2.訪問Redis錯誤,這種情況返回給用戶,讓其重試即可
3.訪問Redis超時,這種情況下,其實可能庫存已經扣減成功,此時不用再重試,免費產生更多的無效扣減,雖然多了一次扣減,但是總數是不變的,只會少賣不會多賣。
?
?
少賣問題
少賣什么情況會出現呢?庫存減少了,但用戶訂單沒生成。
什么情況會這樣呢?有幾種可能:
1..上面提到的,減少庫存操作超時,但實際是成功的,因為超時并不會進入生成訂單流程;
2.在Redis操作成功,但是向Kafka發送消息失敗,這種情況也會白白消耗Redis中的庫存。
說白了,我們只需要保證Redis庫存+ Kafka消耗的最終一致性。
●第一種,也最簡單的方式,在投遞Kafka失敗的情況下,增加漸進式重試;?
(成功的可能性越來越小?他就越來越懶)
●第二種,更安全一點,就是在第一種的基礎上,將這條消息記錄在磁盤上,慢慢重試;
●第三種,寫磁盤之前就可能失敗,可以考慮走WAL路線,但是這樣做下去說不定就做成MySQL的undo log,
redo log這種WAL技術了,會相當復雜,沒有必要。
一般都用第二種
怎么解決黃牛呢
首先我們可以每個id限購一個
第一步查詢庫存,第二步扣減庫存,需要優化為第一步查詢庫存, 第二步查詢用戶己購買個數,第三步扣減庫存,第四步記錄用戶購買數。(用LUA保證原子性)
這里需要注意的是,如果使用Redis集群,那么Redis的數據分片,需要根據用戶來分Key,不然用戶數據會查詢不到。
有了限購,我們可以保證貨品不會被黃牛占據太多
那么還剩一個問題,黃牛大多是通過代碼來搶購,點擊速度比人點擊快得多,這樣就導致了競爭不公平。(我當時就是用了一個秒殺腳本?說實話?收獲甚微)
怎么解決呢?某個用戶請求接口次數過于頻繁,一般說明是用腳本在跑, 可以只針對該用戶做限制。
針對IP做限制也是常見做的做法,但這樣容易誤殺,主要考慮到使用同一個網絡的用戶,可能都是一個出口IP。 限制IP,會導致正常用戶也受到影響。
更好用的方案是加上一個驗證碼驗證。 驗證碼符合91原則(啊.....),90%的時間,都用在驗證碼輸入上,所以使用腳本點擊的影響會降到很低。
?