微信紅包金額分配的算法

   如下內容轉載自網絡,僅供學習和吐槽 算法

   雖然春節已通過去一段時間,但很多微信羣裏面依舊樂此不疲的在玩發紅包活動,用戶自發的將最初的一個春節拜年的場景功能慢慢演化成一個長尾功能。微信

    用戶在微信中搶紅包時分紅搶包和拆包兩個操做。搶包決定紅包是否還有剩餘金額,但若是行動不夠迅速,在拆包階段可能紅包已經被其餘用戶搶走的狀況。網絡

紅包的金額是在何時算? 據某架構羣騰訊財付通專家反饋,紅包的金額是拆的時候實時計算,而不是預先分配,實時計算基於內存,不須要額外存儲空間,而且實時計算效率也很高。每次拆紅包時,系統取0.01到剩餘平均值*2之間做爲紅包的金額。架構

爲了保證每次操做的原子性,拆包過程當中使用了CAS,確保每次只有一個併發用戶拆包成功。拆包CAS失敗的用戶能夠由系統自動進行重試。但也有可能在重試過程當中被別的用戶搶得先機而空手而歸,所以嚴格意義拆包的調用也未能保證用戶先到先得。併發

基於上面的緣由,當時在羣中提到這種算法有些複雜,微信紅包爲了減小存儲,每次進行了一個理解稍複雜的實時計算。對比大部分架構師想到的預分配金額 的作法,預先分配金額須要將金額保存在一個內存隊列中,若是紅包的份額較多,則須要較大的存儲空間。而微信紅包僅保存 count:balance 這樣2個數字。count指還剩幾我的能夠搶,balance只還剩下的金額。dom

可是預分配金額也並非非得須要額外存儲。好比利用隨機算法,在種子相同的狀況下,隨機數實際上返回的隨機序列也是固定的。如如下Python代碼,對於給定的seed 1024,每次執行返回的結果都是相同的。學習

>>> import random
>>> random.seed(1024)
>>> random.randint(1,100)
80
>>> random.randint(1,100)
49
>>> random.randint(1,100)
39
>>> random.randint(1,100)
83
>>> random.randint(1,100)
88

所以預分配金額也只須要額外存儲一個種子,或利用一些紅包id作加密變換作seed達到零存儲。而在發放紅包時候,無需進行CAS操做,而只須要對剩餘紅包count作一個DECR操做。當count<0時,表示紅包被拆包搶完。因爲DECR是原子操做,無需加鎖,用簡單的方法達到了先拆包先得,原理上不存在早拆包但因爲併發衝突失敗而搶不到紅包的狀況。加密

每一個人分配的金額是:total * random(n) / random_total,不須要重複計算。
random(1)..random(n)不須要保存,由於對於給定的seed,random(1)到random(n)返回是固定的。spa

以上算法評論與對比,與Tim所在僱主的紅包算法無關,特此聲明。架構設計

部分細節下面列表已作說明,未作詳細闡述。

Reference:
一、微信紅包的架構設計簡介
二、網友周航老師基於聊天記錄整理的微信紅包架構圖(點擊查看大圖)

相關文章
相關標籤/搜索