說(shuō)明:普通紅包是指金額每份金額固定的紅包包括群普通紅包和個(gè)人普通紅包,個(gè)人普通紅包也就是紅包個(gè)數(shù)為1的群普通紅包。
1 需求分析
一個(gè)字:錢(qián);兩個(gè)字:消遣
1.1用戶為什么要發(fā)紅包?
(1)逗別人玩自己開(kāi)心
有些人發(fā)一些1分錢(qián)的紅包,看到大家哄搶,自己覺(jué)得很爽;有些人自己發(fā)1個(gè)0.01的自己搶和別人比拼速度,這些無(wú)聊的人追求的是娛樂(lè)性,如同黑白快、2048等,滿足無(wú)聊的人消耗時(shí)間就可以了。
(2)成為焦點(diǎn)人物
當(dāng)你經(jīng)常在群里發(fā)紅包的時(shí)候,你就會(huì)成為「群明星」,讓更多人認(rèn)識(shí)你,和你說(shuō)話,你有一種自己朋友遍天下的錯(cuò)覺(jué),然而并沒(méi)有什么卵用,人家是沖著你的錢(qián)來(lái)的。所以就有了【我發(fā)的紅包總數(shù)】【紅包被搶提醒】
(3)獲得關(guān)注賣廣告
單純發(fā)一個(gè)廣告不但沒(méi)有人看,而且會(huì)引起反感。但是你發(fā)個(gè)大紅包,群里面的人會(huì)喜聞樂(lè)見(jiàn),而且很親切的問(wèn)你項(xiàng)目的相關(guān)內(nèi)容或者幫你填寫(xiě)調(diào)查問(wèn)卷。不過(guò)后來(lái)小紅包廣告漸漸失去吸引力,因?yàn)榇蠹业呐d奮閾值提高了,而且重復(fù)的東西是不可能讓用戶持續(xù)高潮的,如同你xxoo的時(shí)候不能總是使用一個(gè)體位一樣。因此對(duì)于服務(wù)號(hào)的搖一搖紅包和關(guān)注紅包,最少也有2元,而且還能裂變給你好友。2塊錢(qián)是什么?官方的說(shuō)法是一張彩票的價(jià)格,一份希望,2元彩票長(zhǎng)期已經(jīng)在廣大群眾心理建立了一個(gè)閾值,一份希望的閾值,『萬(wàn)一實(shí)現(xiàn)呢?』這種心理。而且這種希望還能傳遞給別人(裂變紅包),何樂(lè)而不為呢?
(4)純粹是一種祝福
有時(shí)候是我們產(chǎn)品經(jīng)理想太多了,人家可能僅僅是把傳統(tǒng)的紅包以微信紅包這種新穎的方式發(fā)出來(lái)而已。以前只有結(jié)婚的人才能發(fā)紅包,現(xiàn)在可以全民發(fā),我也可以給朋友帶去一份祝福。不過(guò)包多少呢?這個(gè)很讓人糾結(jié),太少不體面;給『上層』的人發(fā)紅包,人家閾值高,太多支付不起。于是就有了【隨機(jī)紅包這個(gè)東西了】
1.2 用戶為什么要搶紅包?
(1)好玩刺激
這個(gè)理由還是留給那些無(wú)聊的人,不解釋,跟『為什么要發(fā)紅包?』的第一點(diǎn)差不多。那個(gè)【最佳手氣】,就刺激了人們玩紅包接龍(不是某寶那個(gè)坑爹的紅包接龍…)
(2)貪婪——人類原始的欲望
在法律和道德重重的壓制下,深深地掩蓋了人的本性,當(dāng)有這種合法而且又光明正大的"搶錢(qián)",即使是0.01,也足以讓人們壓制的貪欲井噴,造就了微信紅包的繁榮。雖然官方說(shuō),搖紅包是為了讓老一輩了解我們的世界,了解我們的生活,讓我們過(guò)年回家能一起搖紅包??墒菑呐笥讶Γ瑥男侣?,大家在群里的反應(yīng),我一點(diǎn)都沒(méi)感覺(jué)到紅包讓家人團(tuán)聚在一起,不知道那是否是公關(guān)說(shuō)辭,這里不作評(píng)價(jià),而對(duì)人性的激發(fā)確是徹徹底底的。正如所有的自然科學(xué)最終都會(huì)回歸到哲學(xué)問(wèn)題上,所有的產(chǎn)品也終究要回歸到對(duì)人性的思考上。(廢話說(shuō)太多了~~~)
(3)炫耀
證明自己?jiǎn)紊?0年,哦!不對(duì),應(yīng)該是證明自己手速快(不都是一個(gè)意思嘛,廢話真多?。┯械娜藷o(wú)聊到自己發(fā)自己搶,以此在炫耀自己的4G網(wǎng)絡(luò)、光纖還有…麒麟臂。
(4)減少損失
很多人發(fā)了拼手氣紅包覺(jué)得自己錢(qián)包大出血,于是自己又搶了一把,希望自己搶到大一點(diǎn)的金額,相當(dāng)于發(fā)少一點(diǎn)紅包。
1.3 為什么要曬紅包?
(1)炫富心理——我發(fā)出的紅包統(tǒng)計(jì)頁(yè)面
(2)攀比心理——紅包結(jié)果頁(yè)面
這里就不多作解釋了,想想你為什么喜歡在朋友圈發(fā)東西就懂了。
2 入口
1
入口主要分為兩大類:聊天窗口和微信錢(qián)包。
2
2.1錢(qián)包
在錢(qián)包添加紅包入口,是因?yàn)橛脩羰状问褂脮r(shí),一般是先收到別人的紅包,自己要取錢(qián),那么去哪里取呢?肯定是錢(qián)包,錢(qián)包需要集合所有跟錢(qián)有關(guān)的概念,給用戶一個(gè)深刻的印象,類似于OmniFocis的透視功能(不知道就算了…),需要把相關(guān)內(nèi)容聚合到一個(gè)入口。所以錢(qián)包聚合了和錢(qián)相關(guān)的內(nèi)容,比如信用卡還款、手機(jī)充值、理財(cái)通等,用戶第一次進(jìn)來(lái)收錢(qián)的時(shí)候,自然就看到微信紅包并進(jìn)一步引導(dǎo)用戶綁定信用卡和發(fā)紅包。另外如果用戶第一次使用紅包不是收到別人紅包,而是聽(tīng)說(shuō)有紅包這一功能或者看到別人發(fā)紅包,他首先會(huì)想到錢(qián)相關(guān)的東西應(yīng)該在紅包里面。
3
2.2 聊天窗口
而這聊天窗口中加入紅包入口則是更加簡(jiǎn)單粗暴,用戶在過(guò)年或者平常使用會(huì)經(jīng)常點(diǎn)開(kāi)"+"發(fā)送圖片,這就很容易會(huì)見(jiàn)到紅包入口了,而且微信在過(guò)年的時(shí)候特意把紅包按鈕用紅色高亮顯示了,這就更加容易被用戶發(fā)現(xiàn),從而提高入口轉(zhuǎn)換率。這里還有個(gè)邏輯,在單聊和群聊所進(jìn)入的紅包頁(yè)面的不同的,如下圖所示:
4
群紅包默認(rèn)為拼手氣群紅包而不是定額紅包,為什么要醬紫呢?先看看拼手氣群紅包的優(yōu)勢(shì):
1、金額隨機(jī),時(shí)大時(shí)小的金額能給用戶驚喜;
2、可以看到其他用戶搶了多少,引起攀比心理(這次搶得不爽,下次一定要搶個(gè)大大噠);
3、產(chǎn)生很多新奇玩法,比如手氣最佳的發(fā)3倍金額;
4、由于可以看到誰(shuí)搶了紅包,所以群里面總是搶第一又不參與游戲的人基本上是使用外掛軟件,群成員自發(fā)的要求群主踢掉這個(gè)人,這種眾包式的"反外掛"比微信自己使用技術(shù)手段去解決更加節(jié)省成本和更加有效。
至于拼手氣群紅包相對(duì)于普通紅包的劣勢(shì)就是需要大量的計(jì)算資源去計(jì)算紅包的隨機(jī)金額,不過(guò)對(duì)于騰訊那么厲害的架構(gòu)師和財(cái)力,這些計(jì)算資源算不了什么,反而消耗這些資源去拉起微信群的活躍度和拉高同時(shí)在線人數(shù)讓財(cái)報(bào)好看點(diǎn)更加劃算。
2.3 搖一搖
微信在春節(jié)前還額外的增加了搖一搖的紅包入口,給一直被認(rèn)為"約炮神器"的搖一搖洗白(哈哈,開(kāi)玩笑啦!)。加速度傳感器也很具有互動(dòng)性,卻一直隱藏在手機(jī)里面,使用率不如攝像頭和話筒。搖一搖紅包很好的利用了每個(gè)人手機(jī)里面"雪藏"的硬件。在"紅包肯定是要發(fā)的"和"搖一搖功能的代碼本來(lái)就有"的兩大前提下,增加搖一搖紅包這功能并不會(huì)增加多少開(kāi)發(fā)量和成本,因?yàn)榧热患t包要發(fā),無(wú)論用什么形式發(fā),后臺(tái)的負(fù)載均衡和高并發(fā)分流是肯定要做的,搖一搖的代碼在約pao的時(shí)代就已經(jīng)很完善了基本上不用改,接入紅包的邏輯就可以了,所以機(jī)會(huì)成本很低。那為什么一定要發(fā)紅包呢?因?yàn)樯弦荒暌呀?jīng)帶壞頭了,示范效應(yīng)導(dǎo)致支付寶也來(lái)分一杯羹,微信能不發(fā)嗎?
3 界面
3.1發(fā)紅包頁(yè)面
在單人聊天窗口進(jìn)入的普通(定向)紅包的頁(yè)面只需要輸入紅包金額和祝福語(yǔ),點(diǎn)擊【塞錢(qián)進(jìn)紅包】,如果已經(jīng)綁定銀行卡,則調(diào)起對(duì)話框浮層【輸入密碼】;如果未綁定銀行卡則跳轉(zhuǎn)到零錢(qián)支付頁(yè)面,點(diǎn)擊按鈕【使用零錢(qián)支付】即可,無(wú)需輸入密碼,在這個(gè)過(guò)程中,如果零錢(qián)不足,則會(huì)跳轉(zhuǎn)到輸入銀行卡號(hào)的頁(yè)面,點(diǎn)擊【下一步】之后需要接著輸入姓名、銀行預(yù)留手機(jī)號(hào)和短信驗(yàn)證碼,填寫(xiě)完成后即可用銀行卡支付。
5
這里不得不提的是一個(gè)非常人性化的設(shè)計(jì),當(dāng)點(diǎn)擊"改完普通紅包",從群手氣紅包切換到普通紅包的過(guò)程中,已經(jīng)輸入的內(nèi)容不會(huì)丟失,紅包個(gè)數(shù)不變,此時(shí)的單個(gè)金額EditView(安卓UI控件)中的值會(huì)由 總金額/紅包個(gè)數(shù) 得出并自動(dòng)填充;當(dāng)點(diǎn)擊"改為群手氣紅包",從普通紅包切換到群手氣紅包的過(guò)程中,已經(jīng)輸入的內(nèi)容不會(huì)丟失,紅包個(gè)數(shù)不變,此時(shí)的總金額EditView中的值會(huì)由 單個(gè)金額*紅包個(gè)數(shù) 計(jì)算出并自動(dòng)填充,,不用用戶重新輸入,非常貼心。這也是微信"將用戶體驗(yàn)做到極致"的地方之一。
3.2紅包『搶』頁(yè)面
聊天窗口會(huì)顯示出紅包樣式的聊天消息,點(diǎn)擊紅包后會(huì)出現(xiàn)拆的頁(yè)面。
6
3.3紅包『拆』頁(yè)面
點(diǎn)擊按鈕【拆】之后,那坨黃色的東西會(huì)轉(zhuǎn)(用幾幀圖片切換形成的動(dòng)畫(huà),在IOS上比Android上運(yùn)行起來(lái)更加流暢),那坨東西轉(zhuǎn)完之后頁(yè)面會(huì)跳轉(zhuǎn)到【紅包結(jié)果頁(yè)面】。值得一提的是安卓最新版本中將Html版本的紅包換成了安卓原生紅包界面,為什么這么做呢?
一是微信慣用的犧牲客戶端資源(CPU、內(nèi)存、儲(chǔ)存卡容量)去換取服務(wù)器端的穩(wěn)定和減少資源投入的策略,頁(yè)面資源放在本地,這樣子web前端服務(wù)器容量就可以減少投入,同時(shí)也可以減少客戶端對(duì)資源服務(wù)器的訪問(wèn)量。類似的,微信的聊天記錄是默認(rèn)不存儲(chǔ)在服務(wù)器端的,而是將各種圖片語(yǔ)音小視頻全部塞到你手機(jī)的內(nèi)存里面,微信表情在6.0版本之前也是不保存到服務(wù)器的。
二是以往基于web的紅包頁(yè)面經(jīng)常會(huì)出現(xiàn)"媽的頁(yè)面還在loading紅包就沒(méi)了""紅包來(lái)了卻連不了網(wǎng)是怎樣一種體驗(yàn)"等等的用戶抱怨,而原生的頁(yè)面因?yàn)榉旁诒镜夭恍枰h(yuǎn)程加載,只需要傳輸簡(jiǎn)單的紅包ID,發(fā)送者等少量信息即可通知客戶端顯示紅包頁(yè)面,可以減少聯(lián)網(wǎng)時(shí)間和降低網(wǎng)絡(luò)狀況對(duì)搶紅包的體驗(yàn)流暢度,讓用戶搶不到紅包都不會(huì)覺(jué)得是因?yàn)槲⑿艣](méi)優(yōu)化好,而是自己太幸福 (沒(méi)單身的手速慢,哈哈)。下圖為幾種紅包"拆"頁(yè)面(大家來(lái)玩找不同,嘻嘻):
7
那這四個(gè)頁(yè)面分別會(huì)在什么時(shí)候出現(xiàn)呢?在5.2中會(huì)做詳細(xì)的介紹。
3.4紅包結(jié)果頁(yè)面
紅包結(jié)果頁(yè)面會(huì)顯示搶到紅包的人的列表,其中金額最大的為手氣最佳。當(dāng)有兩個(gè)或者以上金額相同的時(shí)候,以時(shí)間最早的一個(gè)為最佳手氣。頁(yè)面還會(huì)顯示發(fā)紅包的人極其昵稱、你自己領(lǐng)到的金額(如果沒(méi)領(lǐng)到就不會(huì)顯示),零錢(qián)入口和轉(zhuǎn)發(fā)該紅包的入口、我的紅包記錄入口。紅包結(jié)果頁(yè)面也有很多種,詳見(jiàn)本文的5.3部分.
8
3.5搖一搖紅包
9
搖一搖紅包和企業(yè)紅包的隨機(jī)方法和群手氣紅包大同小異,由于沒(méi)有接觸過(guò)企業(yè)紅包的發(fā)放流程,這里不多說(shuō)。
為什么要有剩余紅包個(gè)數(shù)呢?
引用鵬飛在人人都是產(chǎn)品經(jīng)理舉辦的產(chǎn)品經(jīng)理大會(huì)廣州站上說(shuō)的一句話"給用戶一個(gè)預(yù)期,現(xiàn)在還有沒(méi)有紅包,還有多少,而且這個(gè)數(shù)字必須準(zhǔn)確,不能忽悠用戶。有些朋友和我說(shuō),他們就是在最后幾秒搖到的。所以,要讓用戶為希望而搖,為了希望,把手搖斷,又算什么!"。沒(méi)錯(cuò),這個(gè)數(shù)字是"準(zhǔn)確"的,但是他并不是實(shí)時(shí)的。因?yàn)檫^(guò)于頻繁刷新的數(shù)字少量減少,不僅用戶沒(méi)有感知,不停的訪問(wèn)數(shù)據(jù)庫(kù)剩余紅包數(shù)對(duì)于服務(wù)器也是極大壓力,所以推測(cè)微信是采用這種策略:每減少1個(gè)單位(比如說(shuō)50W)的紅包數(shù)量,自動(dòng)將這個(gè)值寫(xiě)入緩存服務(wù)器,用戶搖紅包的時(shí)候都直接訪問(wèn)緩存,而且不是每次搖都訪問(wèn)剩余數(shù),而是搖n次之后(比如搖了5次)才去請(qǐng)求一次剩余紅包數(shù),這樣就把傳遞到服務(wù)器的壓力減少n倍。
上圖最后那個(gè)頁(yè)面你沒(méi)見(jiàn)過(guò)?
微信官方說(shuō),當(dāng)服務(wù)器壓力過(guò)大的時(shí)候,喚起讓用戶休息一下這個(gè)頁(yè)面。這里我提出另外一種策略,也許微信也采用了這種策略:當(dāng)用戶搖一搖請(qǐng)求紅包時(shí),服務(wù)器壓力過(guò)大,網(wǎng)絡(luò)阻塞或者隊(duì)列已滿等異常情況下,會(huì)直接通知客戶端"你沒(méi)有搶到",也就是直接返回那個(gè)搖紅包的頁(yè)面進(jìn)行下一次的搖一搖動(dòng)作,這樣子永遠(yuǎn)也不會(huì)顯示那個(gè)"休息一下"的頁(yè)面。
4后臺(tái)
4.1數(shù)據(jù)庫(kù)
以下關(guān)系型數(shù)據(jù)庫(kù)設(shè)計(jì)的字段是基于少量請(qǐng)求下,我們模擬紅包系統(tǒng)的可行方案,并沒(méi)有考慮高并發(fā)、分庫(kù)分表以及緩存的情況,關(guān)于這部分內(nèi)容可以查看本文4.4部分整理一些大神的回答作為了解。
(1)用戶信息數(shù)據(jù)表user_info
userID、紅包ID、祝福語(yǔ)、紅包類型、紅包個(gè)數(shù)、紅包金額、超時(shí)
(2)用戶錢(qián)包數(shù)據(jù)表user_wallet
userID、money、銀行卡ID等其他字段
(3)發(fā)送紅包數(shù)據(jù)表red_send
紅包ID、senderID、紅包個(gè)數(shù)、紅包金額、祝福語(yǔ)、最佳手氣、發(fā)出時(shí)間
(4)接收紅包數(shù)據(jù)表red_receive
紅包ID、receiver、接收時(shí)間、接收金額
4.2隨機(jī)算法
很多人說(shuō)紅包序列是預(yù)先在手機(jī)發(fā)出去的時(shí)候已經(jīng)產(chǎn)生好隨機(jī)序列,其實(shí)這樣會(huì)產(chǎn)生大量的數(shù)據(jù)庫(kù)讀寫(xiě)操作,內(nèi)存讀的速度以DDR3-2400為例,能達(dá)到17G/s,寫(xiě)的速度達(dá)到18G/s(參考文獻(xiàn):http://m.it168.com/article_1410707_p5.html)。而硬盤(pán)數(shù)據(jù)庫(kù)的讀寫(xiě)速度最多達(dá)到133MB/s??梢?jiàn)大量的從硬盤(pán)讀寫(xiě)數(shù)據(jù)不但容易使硬盤(pán)損壞,更達(dá)不到高并發(fā)的讀寫(xiě)需求。所以預(yù)先生成隨機(jī)序列寫(xiě)入數(shù)據(jù)庫(kù),用戶搶的時(shí)候再讀出紅包金額并將用戶信息寫(xiě)入數(shù)據(jù)庫(kù)并不科學(xué)。所以采用內(nèi)存實(shí)時(shí)計(jì)算隨機(jī)序列并異步寫(xiě)入硬盤(pán)數(shù)據(jù)庫(kù)儲(chǔ)存的方法?;趦?nèi)存的隨機(jī)序列是偽隨機(jī)序列,他并不是真正的隨機(jī),而是根據(jù)種子通過(guò)一定的算法計(jì)算出來(lái)的值,只要種子不變,每次計(jì)算出來(lái)的值的序列是一致的。也就是說(shuō)當(dāng)紅包指紋(ID或者ID+時(shí)間戳或者其他算法生成)一定時(shí),計(jì)算出來(lái)的序列是一致的,這樣子就不用儲(chǔ)存在數(shù)據(jù)庫(kù),而是實(shí)時(shí)計(jì)算,第一次取序列的第一個(gè)值,第二次取序列的第二個(gè)值,如此類推。(更詳細(xì)的說(shuō)明可以參考http://www.open-open.com/lib/view/open1430473257443.html)。具體步驟如下(代碼以python舉例子,沒(méi)辦法知道人家后臺(tái)用什么語(yǔ)音寫(xiě)的):
以紅包ID為種子
>>>red_ID = 1775509988475009
>>>random.seed(red_ID)
群手氣紅包的最小值為0.01,搖一搖紅包的最小值為2.00
>>>min = 1.00
>>>if (紅包為群手氣紅包):
min = 0.01
else(紅包為搖一搖紅包):
min = 2.00
群手氣紅包的最大值為剩余紅包總額和個(gè)數(shù)的商的2倍(你可以在群里不停地發(fā)紅包做回歸,記得叫上我去拿紅包,哈哈)。
>>>max = (remain_money/remain_num)*2
而搖一搖紅包官方給出的計(jì)算公式是剩余金額/剩余紅包數(shù)*n
n主觀猜測(cè)也是等于2,在這公司基礎(chǔ)上再人為控制概率。
方案一:
人為干擾概率的,有人拿到京東618元的紅包,動(dòng)腦子想想,京東店慶是618,這個(gè)金額絕對(duì)不是隨機(jī)出來(lái)的,而是設(shè)定好金額,然后每個(gè)金額范圍都有一定的概率。
比如說(shuō)2元—5元概率為85%;5元—20元概率為10%,20元—50元概率為4.99%,618元概率為0.01%。(概率僅作參考,因?yàn)闃颖玖刻?,官方也沒(méi)提供數(shù)據(jù),這里只是提供其中一種可行的方案,以下代碼也只是提供思路,與實(shí)際可運(yùn)行的代碼略有差別)
>>>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 = 剩余金額/剩余紅包數(shù)*n
人為放出618元的彩蛋紅包,并且用上述方法設(shè)置概率為0.0001%
4.3紅包發(fā)出去那一刻發(fā)生了什么?
這一部分由于個(gè)人的水平限制,未能給出有深度的簡(jiǎn)介,這里為了文章的完整性,借用胖胖的文章作為說(shuō)明(胖胖的博客為www.phppan.com)
(1)發(fā)紅包后臺(tái)操作:
在數(shù)據(jù)庫(kù)中增加一條紅包記錄,存儲(chǔ)到CKV,設(shè)置過(guò)期時(shí)間;
在Cache(可能是騰訊內(nèi)部kv數(shù)據(jù)庫(kù),基于內(nèi)存,有落地,有內(nèi)核態(tài)網(wǎng)絡(luò)處理模塊,以內(nèi)核模塊形式提供服務(wù)))中增加一條記錄,存儲(chǔ)搶紅包的人數(shù)N
(2)搶紅包后臺(tái)操作:
搶紅包分為搶和拆,搶操作在Cache層完成,通過(guò)原子減操作進(jìn)行紅包數(shù)遞減,到0就說(shuō)明搶光了,最終實(shí)際進(jìn)入后臺(tái)拆操作的量不大,通過(guò)操作的分離將無(wú)效請(qǐng)求直接擋在Cache層外面。這里的原子減操作并不是真正意義上的原子減操作,是其Cache層提供的CAS,通過(guò)比較版本號(hào)不斷嘗試,存在一定程度上的沖突,沖突的用戶會(huì)放行,讓其進(jìn)入下一步拆的操作,這也解釋了為啥有用戶搶到了拆開(kāi)發(fā)現(xiàn)領(lǐng)完了的情況。
拆紅包在數(shù)據(jù)庫(kù)完成,通過(guò)數(shù)據(jù)庫(kù)的事務(wù)操作累加已經(jīng)領(lǐng)取的個(gè)數(shù)和金額,插入一條領(lǐng)取流水,入賬為異步操作,這也解釋了為啥在春節(jié)期間紅包領(lǐng)取后在余額中看不到。拆的時(shí)候會(huì)實(shí)時(shí)計(jì)算金額,其金額為1分到剩余平均值2倍之間隨機(jī)數(shù),一個(gè)總金額為M元的紅包,最大的紅包為 M * 2 /N(且不會(huì)超過(guò)M),當(dāng)拆了紅包后會(huì)更新剩余金額和個(gè)數(shù)。財(cái)付通按20萬(wàn)筆每秒入賬準(zhǔn)備,實(shí)際只到8萬(wàn)每秒。
4.4 Q&A若干整理(這一部分是網(wǎng)上整理的,不知道如何分類比較好就放在一起了)
①既然在搶的時(shí)候有原子減了就不應(yīng)該出現(xiàn)搶到了拆開(kāi)沒(méi)有的情況?
這里的原子減并不是真正意義上的原子操作,是Cache層提供的CAS,通過(guò)比較版本號(hào)不斷嘗試。
②cache和db掛了怎么辦?
主備 +對(duì)賬
③有沒(méi)有紅包個(gè)數(shù)沒(méi)了,但余額還有情況?
沒(méi)有,程序最后會(huì)有一個(gè)take all操作以及一個(gè)異步對(duì)賬保障。
④為什么要分離搶和拆?
總思路是設(shè)置多層過(guò)濾網(wǎng),層層篩選,層層減少流量和壓力。這個(gè)設(shè)計(jì)最初是因?yàn)閾尣僮魇菢I(yè)務(wù)層,拆是入賬操作,一個(gè)操作太重了,而且中斷率高。 從接口層面看,第一個(gè)接口純緩存操作,搞壓能力強(qiáng),一個(gè)簡(jiǎn)單查詢Cache擋住了絕大部分用戶,做了第一道篩選,所以大部分人會(huì)看到已經(jīng)搶完了的提示。
⑤搶到紅包后再發(fā)紅包或者提現(xiàn),這里有什么策略嗎?
大額優(yōu)先入賬策略
⑥有沒(méi)有從數(shù)據(jù)上證明每個(gè)紅包的概率是不是均等?
不是絕對(duì)均等,就是一個(gè)簡(jiǎn)單的拍腦袋算法。官方已經(jīng)在產(chǎn)品經(jīng)理大會(huì)上說(shuō)明這是個(gè)拍腦袋的算法了。
⑦發(fā)紅包人的錢(qián)會(huì)不會(huì)凍結(jié)?
是直接實(shí)時(shí)扣掉,不是凍結(jié)。
⑧采用實(shí)時(shí)算出金額是出于什么考慮?
實(shí)時(shí)效率更高,預(yù)算才效率低下。預(yù)算還要占額外存儲(chǔ)。因?yàn)榧t包只占一條記錄而且有效期就幾天,所以不需要多大空間。就算壓力大時(shí),水平擴(kuò)展機(jī)器是。詳見(jiàn)本文4.2的說(shuō)明。
⑨實(shí)時(shí)性:為什么明明搶到紅包,點(diǎn)開(kāi)后發(fā)現(xiàn)沒(méi)有?
答:2014年的紅包一點(diǎn)開(kāi)就知道金額,分兩次操作,先搶到金額,然后再轉(zhuǎn)賬。
2015年的紅包的拆和搶是分離的,需要點(diǎn)兩次,因此會(huì)出現(xiàn)搶到紅包了,但點(diǎn)開(kāi)后告知紅包已經(jīng)被領(lǐng)完的狀況。進(jìn)入到第一個(gè)頁(yè)面不代表?yè)尩?,只表示?dāng)時(shí)紅包還有。詳見(jiàn)本文Jinkey在第五部分的說(shuō)明。
⑩紅包的設(shè)計(jì)
答:微信從財(cái)付通拉取金額數(shù)據(jù)過(guò)來(lái),生成個(gè)數(shù)/紅包類型/金額放到redis集群里,app端將紅包ID的請(qǐng)求放入請(qǐng)求隊(duì)列中,如果發(fā)現(xiàn)超過(guò)紅包的個(gè)數(shù),直接返回。根據(jù)紅包的邏輯處理成功得到令牌請(qǐng)求,則由財(cái)付通進(jìn)行一致性調(diào)用,通過(guò)像比特幣一樣,兩邊保存交易記錄,交易后交給第三方服務(wù)審計(jì),如果交易過(guò)程中出現(xiàn)不一致就強(qiáng)制回歸。
?并發(fā)性處理:紅包如何計(jì)算被搶完?
答:cache會(huì)抵抗無(wú)效請(qǐng)求,將無(wú)效的請(qǐng)求過(guò)濾掉,實(shí)際進(jìn)入到后臺(tái)的量不大。cache記錄紅包個(gè)數(shù),原子操作進(jìn)行個(gè)數(shù)遞減,到0表示被搶光。財(cái)付通按照20萬(wàn)筆每秒入賬準(zhǔn)備,但實(shí)際還不到8萬(wàn)每秒。
?如何保持8w每秒的寫(xiě)入?
答:多主sharding,水平擴(kuò)展機(jī)器。
?查詢紅包分配,壓力大不?
答:搶到紅包的人數(shù)和紅包都在一條cache記錄上,沒(méi)有太大的查詢壓力。
?一個(gè)紅包一個(gè)隊(duì)列?
答:沒(méi)有隊(duì)列,一個(gè)紅包一條數(shù)據(jù),數(shù)據(jù)上有一個(gè)計(jì)數(shù)器字段。
?每領(lǐng)一個(gè)紅包就更新數(shù)據(jù)么?
答:每搶到一個(gè)紅包,就cas更新剩余金額和紅包個(gè)數(shù)。
?紅包如何入庫(kù)入賬?
數(shù)據(jù)庫(kù)會(huì)累加已經(jīng)領(lǐng)取的個(gè)數(shù)與金額,插入一條領(lǐng)取記錄。入賬則是后臺(tái)異步操作。
?入帳出錯(cuò)怎么辦?比如紅包個(gè)數(shù)沒(méi)了,但余額還有?
答:最后會(huì)有一個(gè)take all操作。另外還有一個(gè)對(duì)賬來(lái)保障。
5交互
5.1前后端交互時(shí)序
(1)綁定銀行卡
10
(2)收發(fā)群手氣紅包
11
① 發(fā)起紅包操作
② 銀行扣款邏輯,不成功則返回,成功則進(jìn)行下一步
③ 請(qǐng)求將紅包寫(xiě)入數(shù)據(jù)庫(kù)某個(gè)set,并獲取紅包ID返回客戶端
④ 長(zhǎng)連接通知客戶端成功
⑤ 其他用戶接收到紅包消息,點(diǎn)開(kāi),拆。由于用戶操作的速度遠(yuǎn)遠(yuǎn)低于計(jì)算機(jī)處理速度,所以這打開(kāi)和拆開(kāi)的分離,相當(dāng)于設(shè)置了一道緩沖。另外,點(diǎn)開(kāi)之后,不直接獲取金額,而是先讀取紅包是否領(lǐng)完的緩存,如果沒(méi)領(lǐng)完則顯示【拆】的按鈕。點(diǎn)擊【拆】之后再次訪問(wèn)緩存看紅包是否領(lǐng)完,如果沒(méi)領(lǐng)完,則請(qǐng)求服務(wù)器內(nèi)存計(jì)算隨機(jī)金額并返回客戶端,然后異步寫(xiě)入數(shù)據(jù)庫(kù)。
⑥ 紅包結(jié)果會(huì)寫(xiě)入LIstView(安卓的UI控件名稱,ios也有類似的控件)中,用戶可以馬上看到
⑦ 當(dāng)用戶再次打開(kāi)紅包結(jié)果頁(yè)面時(shí),會(huì)從數(shù)據(jù)庫(kù)讀取最新的結(jié)果列表并更新結(jié)果列表。
(3)收發(fā)普通紅包
① 發(fā)起紅包操作
② 銀行扣款邏輯,不成功則返回,成功則進(jìn)行下一步
③ 選擇發(fā)送對(duì)象(若在聊天窗口中發(fā)起著跳過(guò)這一步)
④ 計(jì)算紅包均值(總額/個(gè)數(shù)),將紅包個(gè)數(shù)和均值寫(xiě)入數(shù)據(jù)庫(kù),返回紅包ID到客戶端
⑤ 其他用戶點(diǎn)開(kāi)紅包,拆,訪問(wèn)紅包個(gè)數(shù)判斷是否大于0,若為T(mén)RUE,則個(gè)數(shù)減1;若為FALSE則通知客戶端顯示【已領(lǐng)完】樣式。
5.2 界面交互
5.2.1 基本流程
13
5.2.2 拆紅包頁(yè)面顯示邏輯
對(duì)群手氣紅包、群普通紅包、普通紅包(其實(shí)就是紅包個(gè)數(shù)為1的群普通紅包)和是否領(lǐng)到和是否領(lǐng)完做3×3×3的交叉分析之后,歸納出以下結(jié)論:
mmexport1442151693886
5.2.3 紅包結(jié)果頁(yè)面顯示邏輯
說(shuō)明:
1 代表有出現(xiàn)該項(xiàng)
"字樣"代表下圖所示區(qū)域的文字內(nèi)容:
16
"按鈕"代表藍(lán)色文字鏈接,如下圖所示:
17
金額是指自己拿到的金額
18
搶到的人是指一個(gè)列表:
19
綠色格子代表沒(méi)有這種邏輯,可能是不出現(xiàn)該頁(yè)面或者其他原因。
對(duì)上表的數(shù)據(jù)進(jìn)行挖掘,我們可以發(fā)現(xiàn)以下規(guī)則集:
(1)當(dāng)領(lǐng)到紅包的時(shí)候,會(huì)顯示按鈕"已存入零錢(qián),可用于發(fā)紅包"、"已存入零錢(qián),可用于消費(fèi)"、"已存入零錢(qián),可用于轉(zhuǎn)賬"、"已存入零錢(qián),可用于提現(xiàn)"的其中一個(gè),順序或隨機(jī)出現(xiàn);并顯示自己所獲得的紅包金額。
(2)當(dāng)自己發(fā)的紅包沒(méi)被領(lǐng)完,會(huì)顯示按鈕"繼續(xù)發(fā)送此紅包";
(3)領(lǐng)到別人發(fā)的紅包時(shí),會(huì)顯示按鈕"查看我的紅包記錄";
(4)對(duì)于群手氣紅包被領(lǐng)完時(shí),如果紅包是自己發(fā)的會(huì)顯示字樣"n個(gè)紅包共n元,n秒被搶光";如果是被人發(fā)的紅包則會(huì)顯示字樣"n個(gè)紅包,n秒被搶光";對(duì)于(群)普通紅包被領(lǐng)完時(shí),會(huì)顯示字樣"n個(gè)紅包共n元";
(5)對(duì)于紅包(個(gè)數(shù)大于1)沒(méi)被領(lǐng)完,自己的紅包會(huì)顯示字樣"已領(lǐng)取x/y個(gè),共x/y元";別人發(fā)的紅包字樣"領(lǐng)取x/y個(gè)";
(6)對(duì)于紅包(個(gè)數(shù)等于1)沒(méi)領(lǐng)完時(shí),會(huì)顯示字樣"紅包金額n元,等待對(duì)方領(lǐng)取";
(7)對(duì)于群手氣紅包和自己發(fā)的普通紅包都會(huì)顯示搶到紅包的人的列表;
(8)已經(jīng)被領(lǐng)完的群手氣紅包才會(huì)顯示"最佳手氣"的標(biāo)識(shí);
從(4)-(6)的規(guī)則我們可以看出,微信做到為什么是一個(gè)優(yōu)秀的產(chǎn)品而不僅僅是一個(gè)及格的產(chǎn)品。自己發(fā)的紅包會(huì)顯示出總金額,自己發(fā)了多少錢(qián)自己心里有數(shù),卻不希望別人看到總的金額(雖然可以根據(jù)列表算出來(lái),但是大部分人不會(huì)去計(jì)算每一個(gè)別人紅包的總金額),避免發(fā)紅包的用戶還要承受"面子問(wèn)題"挫傷用戶發(fā)紅包的積極性。這樣去營(yíng)造一種無(wú)分貴賤貧富,人人都可以發(fā)紅包的氛圍,間接提高發(fā)紅包的人數(shù)和整個(gè)平臺(tái)的活躍度。
5.2.4搖一搖紅包
這一部分因?yàn)閷?xiě)文章的時(shí)候搖一搖紅包活動(dòng)已經(jīng)下線了,所以只能從網(wǎng)上找來(lái)截圖,簡(jiǎn)略地說(shuō)明一下流程。如下圖:
僅以此文,紀(jì)念大學(xué)四年為了加入微信團(tuán)隊(duì)所做出的努力。