大家好,我是小?,一個(gè)漂泊江湖多年的 985 非科班程序員,曾混跡于國(guó)企、互聯(lián)網(wǎng)大廠和創(chuàng)業(yè)公司的后臺(tái)開(kāi)發(fā)攻城獅。
當(dāng)我那天拿著手機(jī),正在和朋友們的微信群里暢聊著八卦新聞和即將到來(lái)的周末計(jì)劃時(shí),忽然一條帶著喜意的消息撲面而來(lái),消息正中間赫然寫(xiě)著八個(gè)大字:恭喜發(fā)財(cái),大吉大利。
圖片
搶紅包!!相信大部分人對(duì)此都不陌生,自 2015 年春節(jié)以來(lái),微信就新增了各類型搶紅包功能,吸引了數(shù)以億萬(wàn)級(jí)的用戶參與體驗(yàn),今天,我們就來(lái)聊一聊這個(gè)奇妙有趣的紅包系統(tǒng)。
圖片
搶紅包系統(tǒng)從功能拆分,可以分為包紅包、發(fā)紅包、搶紅包和拆紅包 4 個(gè)功能。
對(duì)于系統(tǒng)特性來(lái)說(shuō),搶紅包系統(tǒng)和秒殺系統(tǒng)類似。
圖片
每次發(fā)紅包都是一次商品秒殺流程,包括商品準(zhǔn)備,商品上架,查庫(kù)存、減庫(kù)存,以及秒殺開(kāi)始,最終的用戶轉(zhuǎn)賬就是紅包到賬的過(guò)程。
相比秒殺活動(dòng),微信發(fā)紅包系統(tǒng)的用戶量更大,設(shè)計(jì)更加復(fù)雜,需要重視的點(diǎn)更多,主要包括以下幾點(diǎn)。
海量并發(fā)請(qǐng)求,秒殺只有一次活動(dòng),但紅包可能同一時(shí)刻有幾十萬(wàn)個(gè)秒殺活動(dòng)。
比如 2017 雞年除夕,微信紅包搶紅包用戶數(shù)高達(dá) 3.42 億,收發(fā)峰值 76 萬(wàn)/秒,發(fā)紅包 37.77 億 個(gè)。
紅包業(yè)務(wù)涉及資金交易,所以一定不能出現(xiàn)超賣、少賣的情況。
參與用戶越多,并發(fā) DB 請(qǐng)求越大,數(shù)據(jù)越容易出現(xiàn)事務(wù)問(wèn)題,所以系統(tǒng)得做好事務(wù)一致性。
這也是一般秒殺活動(dòng)的難點(diǎn)所在,而且搶紅包系統(tǒng)涉及金錢(qián)交易,所以事務(wù)級(jí)別要求更高,不能出現(xiàn)臟數(shù)據(jù)。
搶紅包功能允許用戶在群聊中發(fā)送任意個(gè)數(shù)和金額的紅包,群成員可以搶到隨機(jī)金額的紅包,但要保證每個(gè)用戶的紅包金額不小于 0.01 元。
圖片
搶紅包的詳細(xì)交互流程如下:
紅包表 redpack 的字段如下:
該表用來(lái)記錄用戶發(fā)了多少紅包,以及需要維護(hù)的剩余金額。
紅包記錄表 redpack_record 如下:
記錄表用來(lái)存放用戶具體搶到的紅包信息,也是紅包表的副表。
從 2015 年起,微信紅包的搶紅包和拆紅包就分離了,用戶點(diǎn)擊搶紅包后需要進(jìn)行兩次操作。
這也是為什么明明有時(shí)候搶到了紅包,點(diǎn)開(kāi)后卻發(fā)現(xiàn)該紅包已經(jīng)被領(lǐng)取完了。
圖片
搶紅包的交互步驟如下:
上述流程,在一般的秒殺活動(dòng)中隨處可見(jiàn),但是,紅包系統(tǒng)真的有這么簡(jiǎn)單嗎?
當(dāng)用戶量過(guò)大時(shí),高并發(fā)下的事務(wù)一致性怎么保證,數(shù)據(jù)分流如何處理,紅包的數(shù)額分配又是怎么做的,接下來(lái)我們一一探討。
由于是秒殺類設(shè)計(jì),以及 money 分發(fā),所以我們重點(diǎn)關(guān)注搶紅包時(shí)的高并發(fā)解決方案和紅包分配算法。
首先,搶紅包系統(tǒng)的用戶量很大,如果幾千萬(wàn)甚至億萬(wàn)用戶同時(shí)在線發(fā)搶紅包,請(qǐng)求直接打到數(shù)據(jù)庫(kù),必然會(huì)導(dǎo)致后端服務(wù)過(guò)載甚至崩潰。
而在這種業(yè)務(wù)量下,簡(jiǎn)單地對(duì)數(shù)據(jù)庫(kù)進(jìn)行擴(kuò)容不僅會(huì)讓成本消耗劇增,另一方面由于存在磁盤(pán)的性能瓶頸,所以大概率解決不了問(wèn)題。
所以,我們將解決方案集中在 減輕系統(tǒng)壓力、提升響應(yīng)速度 上,接下來(lái)會(huì)從緩存、加鎖、異步分治等方案來(lái)探討可行性。
和大多數(shù)秒殺系統(tǒng)設(shè)計(jì)相似,由于搶紅包時(shí)并發(fā)很高,如果直接操作 DB 里的數(shù)據(jù)表,可能觸發(fā) DB 鎖的邏輯,導(dǎo)致響應(yīng)不及時(shí)。
圖片
所以,我們可以在 DB 落盤(pán)之前加一層緩存,先限制住流量,再處理紅包訂單的數(shù)據(jù)更新。
這樣做的優(yōu)點(diǎn)是用緩存操作替代了磁盤(pán)操作,提升了并發(fā)性能,這在一般的小型秒殺活動(dòng)中非常有效!
但是,隨著微信使用發(fā)&搶紅包的用戶量增多,系統(tǒng)壓力增大,各種連鎖反應(yīng)產(chǎn)生后,數(shù)據(jù)一致性的問(wèn)題逐漸暴露出來(lái):
而且在幾十萬(wàn)的并發(fā)下,直接對(duì)業(yè)務(wù)加鎖也是不現(xiàn)實(shí)的,即便是樂(lè)觀鎖。
在關(guān)系型 DB 里,有兩種并發(fā)控制方法:分為樂(lè)觀鎖(又叫樂(lè)觀并發(fā)控制,Optimistic Concurrency Control,縮寫(xiě) “OCC”)和悲觀鎖(又叫悲觀并發(fā),Pessimistic Concurrency Control,縮寫(xiě)“PCC”)。
圖片
悲觀鎖在操作數(shù)據(jù)時(shí)比較悲觀,認(rèn)為別的事務(wù)可能會(huì)同時(shí)修改數(shù)據(jù),所以每次操作數(shù)據(jù)時(shí)會(huì)先把數(shù)據(jù)鎖住,直到操作完成。
樂(lè)觀鎖正好相反,這種策略主打一個(gè)“信任”的思想,認(rèn)為事務(wù)之間的數(shù)據(jù)競(jìng)爭(zhēng)很小,所以在操作數(shù)據(jù)時(shí)不會(huì)加鎖,直到所有操作都完成到提交時(shí)才去檢查是否有事務(wù)更新(通常是通過(guò)版本號(hào)來(lái)判斷),如果沒(méi)有則提交,否則進(jìn)行回滾。
在高并發(fā)場(chǎng)景下,由于數(shù)據(jù)操作的請(qǐng)求很多,所以樂(lè)觀鎖的吞吐量更大一些。但是從業(yè)務(wù)來(lái)看,可能會(huì)帶來(lái)一些額外的問(wèn)題:
總的來(lái)說(shuō),樂(lè)觀鎖適用于數(shù)據(jù)競(jìng)爭(zhēng)小,沖突較少的業(yè)務(wù)場(chǎng)景,而悲觀鎖也不適用于高并發(fā)場(chǎng)景的數(shù)據(jù)更新。
因此對(duì)于搶紅包系統(tǒng)來(lái)說(shuō),加鎖是非常不適合的。
綜上所述,搶紅包時(shí)不僅要解決高并發(fā)問(wèn)題、還得保障并發(fā)的順序性,所以我們考慮從隊(duì)列的角度來(lái)設(shè)計(jì)。
我們知道,每次包紅包、發(fā)紅包、搶紅包時(shí),也有先后依賴關(guān)系,因此我們可以將紅包 ID 作為一個(gè)唯一 Key,將發(fā)一次紅包看作一個(gè)單獨(dú)的 set,各個(gè) set 相互獨(dú)立處理。
圖片
這樣,我們就把海量的搶紅包系統(tǒng)分成一個(gè)個(gè)的小型秒殺系統(tǒng),在調(diào)度處理中,通過(guò)對(duì)紅包 ID 哈希取模,將一個(gè)個(gè)請(qǐng)求打到多臺(tái)服務(wù)器上解耦處理。
然后,為了保證每個(gè)用戶搶紅包的先后順序,我們把一個(gè)紅包相關(guān)的操作串行起來(lái),放到一個(gè)隊(duì)列里面,依次消費(fèi)。
從上述 set 分流我們可以看出,一臺(tái)服務(wù)器可能會(huì)同時(shí)處理多個(gè)紅包的操作,所以,為了保證消費(fèi)者處理 DB 不被高并發(fā)打崩,我們還需要在消費(fèi)隊(duì)列時(shí)用緩存來(lái)限制并發(fā)消費(fèi)數(shù)量。
搶紅包業(yè)務(wù)消費(fèi)時(shí)由于不存儲(chǔ)數(shù)據(jù),只是用緩存來(lái)控制并發(fā)。所以我們可以選用大數(shù)據(jù)量下性能更好的 Memcached。
除此之外,在數(shù)據(jù)存儲(chǔ)上,我們可以用紅包 ID 進(jìn)行哈希分表,用時(shí)間維度對(duì) DB 進(jìn)行冷熱分離,以此來(lái)提升單 set 的處理性能。
綜上所述,搶紅包系統(tǒng)在解決高并發(fā)問(wèn)題上采用了 set 分治、串行化隊(duì)列、雙維度分庫(kù)分表 等方案,使得單組 DB 的并發(fā)性能得到了有效提升,在應(yīng)對(duì)數(shù)億級(jí)用戶請(qǐng)求時(shí)取得了良好的效果。
搶紅包后,我們需要進(jìn)行拆紅包,接下來(lái)我們討論一下紅包系統(tǒng)的紅包分配算法。
紅包金額分配時(shí),由于是隨機(jī)分配,所以有兩種實(shí)現(xiàn)方案:實(shí)時(shí)拆分和預(yù)先生成。
實(shí)時(shí)拆分,指的是在搶紅包時(shí)實(shí)時(shí)計(jì)算每個(gè)紅包的金額,以實(shí)現(xiàn)紅包的拆分過(guò)程。
這個(gè)對(duì)系統(tǒng)性能和拆分算法要求較高,例如拆分過(guò)程要一直保證后續(xù)待拆分紅包的金額不能為空,不容易做到拆分的紅包金額服從正態(tài)分布規(guī)律。
預(yù)先生成,指的是在紅包開(kāi)搶之前已經(jīng)完成了紅包的金額拆分,搶紅包時(shí)只是依次取出拆分好的紅包金額。
這種方式對(duì)拆分算法要求較低,可以拆分出隨機(jī)性很好的紅包金額,但通常需要結(jié)合隊(duì)列使用。
綜合上述優(yōu)缺點(diǎn)考慮,以及微信群聊中的人數(shù)不多(目前最高 500 人),所以我們采用實(shí)時(shí)拆分的方式,用二倍均值法來(lái)生成隨機(jī)紅包,只滿足隨機(jī)即可,不需要正態(tài)分布。
故可能出現(xiàn)很大的紅包差額,但這更刺激不是嗎
本文鏈接:http://www.www897cc.com/showinfo-26-46358-0.html聽(tīng)說(shuō)你會(huì)架構(gòu)設(shè)計(jì)?來(lái),弄一個(gè)紅包系統(tǒng)
聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com