1. 程式人生 > >搶紅包、秒殺高併發場景的 mysql 高效實現

搶紅包、秒殺高併發場景的 mysql 高效實現

場景分析

這裡以搶紅包場景為例,需求如下:

    1.紅包有個數限制,假設紅包的個數限制為X。
    2.紅包金額上線限制,假設金額上線為Y。
    3.要求使用者搶紅包的時候,不超過紅包的個數限制X。
    4.要求使用者搶紅包的時候,不超過紅包的金額Y。
    5.每個使用者一次紅包活動只能搶一個。

常規思路

這裡提一下最常見的思路:

    1.在使用者搶紅包時,檢查當前發出去紅包數量和金額,並加鎖。
    2.檢查紅包數量和金額正常的後,隨機使用者紅包金額。
    3.然後修改紅包發出去的數量和金額,並給使用者贈送紅包,然後解鎖。

常規思路的優缺點

首先是優點

    1.
思路簡單 2.編不下去了。。。

然後是缺點

    1.鎖資料回造成大量程序等待,造成浪費資源。
    2.鎖造成的等待,使用者體驗奇差。
    3.對於鎖機制不太瞭解的同學會產生一定的危險性。

優化思路

先分析,為什麼常規思路會慢?

    1.在搶紅包的時候,每次都需要檢查紅包的上限 XY2.鎖會造成大量程序卡頓。
    3.生成紅包的金額時還需要檢查與上限 XY 是否有衝突。

優化解決方案

紅包生成前置

例如紅包個數上限為X,金額上限為Y。
那麼,我在活動進行前就把這 X 個紅包插入到資料庫
並生成序號:HB1、HB2、HB3。。。。HBX

那麼實際上,到時候使用者就只需要按照先後順序去領取這個有序的紅包隊列了。
這個操作減少了到時候線上所產生的很多的計算量。最重要的是,能夠簡單且有效的保證了整個活動的可控性。

利用ID自增保證排隊順序

這裡利用到了一個ID生成表,通過建立 user_id 的唯一索引,保證每個人只能拿到一個序號。

搶紅包步驟如下

    1.活動建立之前,建立一張ID生成表,ID從 1 開始自增,且 user_id 唯一。
    2.活動開始,使用者開始搶紅包操作。
    3.搶紅包之前,先插入ID表,獲取插入ID,如果ID > X,通知使用者已被搶完。
    4.如果 ID <= X,那麼恭喜了,去紅包表領取序號為 ID 的紅包,並走非同步發紅包過程。
    5.活動結束之後,把相關使用者領取資訊儲存在紅包表,刪除ID生成表。

方案優點

    1.不需要程式碼實現鎖機制。
    2.
邏輯簡單。 3.mysql保證每個使用者只能拿到一個,且有序。

更多思考

有些朋友提到,可以用 redis 佇列儲存紅包資訊,但是實際上 redis 比較佔用記憶體,需要長期儲存資料最好還是放在mysql。實際上,這裡可以使用 redis 的 incr 命令,得到類似在上面提到的 ID 生成表的功能,更加快速且嚴格遞增,能夠使整個專案的併發性更高。

轉發請宣告轉發:
原文在這裡:http://www.jianshu.com/p/3ba3c884b635