原創(chuàng):轉(zhuǎn)發(fā)請聲明來源。
場景分析
這里以搶紅包場景為例沙郭,需求如下:
? ? 1.紅包有個數(shù)限制佛呻,假設(shè)紅包的個數(shù)限制為X。
? ? 2.紅包金額上線限制病线,假設(shè)金額上線為Y吓著。
? ? 3.要求用戶搶紅包的時候,不超過紅包的個數(shù)限制X送挑。
? ? 4.要求用戶搶紅包的時候绑莺,不超過紅包的金額Y。
? ? 5.每個用戶一次紅包活動只能搶一個惕耕。
常規(guī)思路
這里提一下最常見的思路:
? ? 1.在用戶搶紅包時纺裁,檢查當(dāng)前發(fā)出去紅包數(shù)量和金額,并加鎖司澎。
? ? 2.檢查紅包數(shù)量和金額正常的后欺缘,隨機(jī)用戶紅包金額。
? ? 3.然后修改紅包發(fā)出去的數(shù)量和金額惭缰,并給用戶贈送紅包浪南,然后解鎖。
常規(guī)思路的優(yōu)缺點
首先是優(yōu)點
? ? 1.思路簡單
? ? 2.編不下去了漱受。络凿。。
然后是缺點
? ? 1.鎖數(shù)據(jù)回造成大量進(jìn)程等待昂羡,造成浪費資源絮记。
? ? 2.鎖造成的等待,用戶體驗奇差虐先。
? ? 3.對于鎖機(jī)制不太了解的同學(xué)會產(chǎn)生一定的危險性怨愤。
優(yōu)化思路
先分析,為什么常規(guī)思路會慢蛹批?
? ? 1.在搶紅包的時候撰洗,每次都需要檢查紅包的上限 X 和 Y篮愉。
? ? 2.鎖會造成大量進(jìn)程卡頓。
? ? 3.生成紅包的金額時還需要檢查與上限 X 跟 Y 是否有沖突差导。
優(yōu)化解決方案
紅包生成前置
例如紅包個數(shù)上限為X试躏,金額上限為Y。
那么设褐,我在活動進(jìn)行前就把這 X 個紅包插入到數(shù)據(jù)庫
并生成序號:HB1颠蕴、HB2、HB3助析。犀被。。外冀。HBX
那么實際上寡键,到時候用戶就只需要按照先后順序去領(lǐng)取這個有序的紅包隊列了。
這個操作減少了到時候線上所產(chǎn)生的很多的計算量锥惋。最重要的是昌腰,能夠簡單且有效的保證了整個活動的可控性。
利用ID自增保證排隊順序
這里利用到了一個ID生成表膀跌,通過建立 user_id 的唯一索引,保證每個人只能拿到一個序號固灵。
搶紅包步驟如下
? ? 1.活動創(chuàng)建之前捅伤,創(chuàng)建一張ID生成表,ID從 1 開始自增巫玻,且 user_id 唯一丛忆。
? ? 2.活動開始,用戶開始搶紅包操作仍秤。
? ? 3.搶紅包之前熄诡,先插入ID表,獲取插入ID诗力,如果ID > X凰浮,通知用戶已被搶完。
? ? 4.如果 ID <= X苇本,那么恭喜了袜茧,去紅包表領(lǐng)取序號為 ID 的紅包,并走異步發(fā)紅包過程瓣窄。
? ? 5.活動結(jié)束之后笛厦,把相關(guān)用戶領(lǐng)取信息存儲在紅包表,刪除ID生成表俺夕。
方案優(yōu)點
1.不需要代碼實現(xiàn)鎖機(jī)制裳凸。? ? 2.邏輯簡單贱鄙。? ? 3.mysql保證每個用戶只能拿到一個,且有序姨谷。
更多思考
有些朋友提到逗宁,可以用 redis 隊列存儲紅包信息,但是實際上 redis 比較占用內(nèi)存菠秒,需要長期存儲數(shù)據(jù)最好還是放在mysql疙剑。實際上,這里可以使用 redis 的 incr 命令践叠,得到類似在上面提到的 ID 生成表的功能言缤,更加快速且嚴(yán)格遞增,能夠使整個項目的并發(fā)性更高禁灼。
作者:簡公介
鏈接:http://www.reibang.com/p/3ba3c884b635
來源:簡書
簡書著作權(quán)歸作者所有管挟,任何形式的轉(zhuǎn)載都請聯(lián)系作者獲得授權(quán)并注明出處。