你所不知道的微信紅包(四)——后臺分析

4后臺

4.1 數據庫

以下關系型數據庫設計的字段是基于少量請求下,我們模擬紅包系統的可行方案,并沒有考慮高并發、分庫分表以及緩存的情況,關于這部分內容可以查看本文4.4部分整理一些大神的回答作為了解。

(1)用戶信息數據表user_info

userID、紅包ID、祝福語、紅包類型、紅包個數、紅包金額、超時

(2)用戶錢包數據表user_wallet

userID、money、銀行卡ID等其他字段

(3)發送紅包數據表red_send

紅包ID、senderID、紅包個數、紅包金額、祝福語、最佳手氣、發出時間

(4)接收紅包數據表red_receive

紅包ID、receiver、接收時間、接收金額

4.2 隨機算法

很多人說紅包序列是預先在手機發出去的時候已經產生好隨機序列,其實這樣會產生大量的數據庫讀寫操作,內存讀的速度以DDR3-2400為例,能達到17G/s,寫的速度達到18G/s(參考文獻:http://m.it168.com/article_1410707_p5.html)。而硬盤數據庫的讀寫速度最多達到133MB/s。可見大量的從硬盤讀寫數據不但容易使硬盤損壞,更達不到高并發的讀寫需求。所以預先生成隨機序列寫入數據庫,用戶搶的時候再讀出紅包金額并將用戶信息寫入數據庫并不科學。所以采用內存實時計算隨機序列并異步寫入硬盤數據庫儲存的方法。基于內存的隨機序列是偽隨機序列,他并不是真正的隨機,而是根據種子通過一定的算法計算出來的值,只要種子不變,每次計算出來的值的序列是一致的。也就是說當紅包指紋(ID或者ID+時間戳或者其他算法生成)一定時,計算出來的序列是一致的,這樣子就不用儲存在數據庫,而是實時計算,第一次取序列的第一個值,第二次取序列的第二個值,如此類推。(更詳細的說明可以參考http://www.open-open.com/lib/view/open1430473257443.html)。具體步驟如下(代碼以python舉例子,沒辦法知道人家后臺用什么語言寫的):

以紅包ID為種子

>>>red_ID = 1775509988475009

>>>random.seed(red_ID)

群手氣紅包的最小值為0.01,搖一搖紅包的最小值為2.00

>>>min = 1.00

>>>if (紅包為群手氣紅包):

min = 0.01

else(紅包為搖一搖紅包):

min = 2.00

群手氣紅包的最大值為剩余紅包總額和個數的商的2倍(你可以在群里不停地發紅包做回歸,記得叫上我去拿紅包,哈哈)。

>>>max = (remain_money/remain_num)*2

而搖一搖紅包官方給出的計算公式是剩余金額/剩余紅包數*n

n主觀猜測也是等于2,在這公式基礎上再人為控制概率。

方案一:

人為干擾概率的,有人拿到京東618元的紅包,動腦子想想,京東店慶是618,這個金額絕對不是隨機出來的,而是設定好金額,然后每個金額范圍都有一定的概率。

比如說2元—5元概率為85%;5元—20元概率為10%,20元—50元概率為4.99%,618元概率為0.01%。(概率僅作參考,因為樣本量太大,官方也沒提供數據,這里只是提供其中一種可行的方案,以下代碼也只是提供思路,與實際可運行的代碼略有差別)

>>>a = random.uniform(0,1)

>>>b,_max,_min = 0

>>>if a < 0.85:

_min = 2.00

_max = 5.00

>>>elif a < 0.95 & a >= 0.85:

_min = 5.00

_max = 20.00

>>>elif a < 0.9999 & a >= 0.95:

_min = 20.00

_max = 50.00

>>>elif a > 0.9999:

_min = 618.00

_max = 618.00

>>>random.uniform(min,max)

方案二:

_min = 2.00

_max = 剩余金額/剩余紅包數*n

人為放出618元的彩蛋紅包,并且用上述方法設置概率為0.0001%

4.3 紅包發出去那一刻發生了什么?

這一部分由于個人的水平限制,未能給出有深度的簡介,這里為了文章的完整性,借用胖胖的文章作為說明(胖胖的博客為www.phppan.com)

(1)發紅包后臺操作:

在數據庫中增加一條紅包記錄,存儲到CKV,設置過期時間;

在Cache(可能是騰訊內部kv數據庫,基于內存,有落地,有內核態網絡處理模塊,以內核模塊形式提供服務))中增加一條記錄,存儲搶紅包的人數N

(2)搶紅包后臺操作:

搶紅包分為搶和拆,搶操作在Cache層完成,通過原子減操作進行紅包數遞減,到0就說明搶光了,最終實際進入后臺拆操作的量不大,通過操作的分離將無效請求直接擋在Cache層外面。這里的原子減操作并不是真正意義上的原子減操作,是其Cache層提供的CAS,通過比較版本號不斷嘗試,存在一定程度上的沖突,沖突的用戶會放行,讓其進入下一步拆的操作,這也解釋了為啥有用戶搶到了拆開發現領完了的情況。

拆紅包在數據庫完成,通過數據庫的事務操作累加已經領取的個數和金額,插入一條領取流水,入賬為異步操作,這也解釋了為啥在春節期間紅包領取后在余額中看不到。拆的時候會實時計算金額,其金額為1分到剩余平均值2倍之間隨機數,一個總金額為M元的紅包,最大的紅包為 M * 2 /N(且不會超過M),當拆了紅包后會更新剩余金額和個數。財付通按20萬筆每秒入賬準備,實際只到8萬每秒。

4.4 Q&A若干整理

(這一部分是網上整理的,不知道如何分類比較好就放在一起了)

① 既然在搶的時候有原子減了就不應該出現搶到了拆開沒有的情況?

這里的原子減并不是真正意義上的原子操作,是Cache層提供的CAS,通過比較版本號不斷嘗試。

② cache和db掛了怎么辦?

主備 +對賬

③ 有沒有紅包個數沒了,但余額還有情況?

沒有,程序最后會有一個take all操作以及一個異步對賬保障。

④ 為什么要分離搶和拆?

總思路是設置多層過濾網,層層篩選,層層減少流量和壓力。這個設計最初是因為搶操作是業務層,拆是入賬操作,一個操作太重了,而且中斷率高。 從接口層面看,第一個接口純緩存操作,搞壓能力強,一個簡單查詢Cache擋住了絕大部分用戶,做了第一道篩選,所以大部分人會看到已經搶完了的提示。

⑤ 搶到紅包后再發紅包或者提現,這里有什么策略嗎?

大額優先入賬策略

⑥ 有沒有從數據上證明每個紅包的概率是不是均等?

不是絕對均等,就是一個簡單的拍腦袋算法。官方已經在產品經理大會上說明這是個拍腦袋的算法了。

⑦發紅包人的錢會不會凍結?

是直接實時扣掉,不是凍結。

⑧ 采用實時算出金額是出于什么考慮?

實時效率更高,預算才效率低下。預算還要占額外存儲。因為紅包只占一條記錄而且有效期就幾天,所以不需要多大空間。就算壓力大時,水平擴展機器是。詳見本文4.2的說明。

⑨ 實時性:為什么明明搶到紅包,點開后發現沒有?

答:2014年的紅包一點開就知道金額,分兩次操作,先搶到金額,然后再轉賬。

2015年的紅包的拆和搶是分離的,需要點兩次,因此會出現搶到紅包了,但點開后告知紅包已經被領完的狀況。進入到第一個頁面不代表搶到,只表示當時紅包還有。詳見本文Jinkey在第五部分的說明。

⑩ 紅包的設計

答:微信從財付通拉取金額數據過來,生成個數/紅包類型/金額放到redis集群里,app端將紅包ID的請求放入請求隊列中,如果發現超過紅包的個數,直接返回。根據紅包的邏輯處理成功得到令牌請求,則由財付通進行一致性調用,通過像比特幣一樣,兩邊保存交易記錄,交易后交給第三方服務審計,如果交易過程中出現不一致就強制回歸。

? 并發性處理:紅包如何計算被搶完?

答:cache會抵抗無效請求,將無效的請求過濾掉,實際進入到后臺的量不大。cache記錄紅包個數,原子操作進行個數遞減,到0表示被搶光。財付通按照20萬筆每秒入賬準備,但實際還不到8萬每秒。

? 如何保持8w每秒的寫入?

答:多主sharding,水平擴展機器。

? 查詢紅包分配,壓力大不?

答:搶到紅包的人數和紅包都在一條cache記錄上,沒有太大的查詢壓力。

? 一個紅包一個隊列?

答:沒有隊列,一個紅包一條數據,數據上有一個計數器字段。

? 每領一個紅包就更新數據么?

答:每搶到一個紅包,就cas更新剩余金額和紅包個數。

? 紅包如何入庫入賬?

數據庫會累加已經領取的個數與金額,插入一條領取記錄。入賬則是后臺異步操作。

? 入帳出錯怎么辦?比如紅包個數沒了,但余額還有?

答:最后會有一個take all操作。另外還有一個對賬來保障。

下一篇:你所不知道的微信紅包(五)——交互分析

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 國家電網公司企業標準(Q/GDW)- 面向對象的用電信息數據交換協議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 11,178評論 6 13
  • 雪壓蒼松橫梗瘦,風憐勁柏豎枝驚。 霜天落葉飄無意,銀嶺叢巒靜有聲。 爐火廳堂溫舊酒,雀飛樓檻迎新晴。 炊煙裊裊呼肴...
    山上人家123閱讀 487評論 9 18
  • 生活中,有兩種人,一種是內向性格,善于向內尋找快樂;一種是外向性格,善于向外界尋求認可……不管是什么性格,我們都需...
    未竹閱讀 291評論 1 4
  • 小時候家里除了沒有錢,啥吃的都有,有菜有水果有魚有肉有骨頭,鄰居小孩經常拿著碗等在我家門口,如果有什么我不想吃的,...
    暖笑如云閱讀 537評論 0 2