说明:普通红包是指金额每份金额固定的红包包含群普通红包和个人普通红包,个人普通红包也就是红包个数为1的群普通红包。
1 需要剖析
一个字:钱;两个字:消遣
1.1用户为何要发红包?
(1)逗其他人玩自己高兴
有的人发一些1分钱的红包,看到大伙哄抢,自己感觉非常爽;有的人自己发1个0.01的自己抢和其他人比拼速度,这类无聊的人追求的是娱乐性,好似黑白快、2048等,满足无聊的人消耗时间就能了。
(2)成为焦点人物
当你常常在群里发红包的时候,你就会成为「群明星」,让更多人认识你,和你说话,你有一种自己朋友遍天下的错觉,然而并没什么卵用,人家是冲着你的钱来的。所以就有了
(3)获得关注卖广告
单纯发一个广告不但无人看,而且会引起反感。但你发个大红包,群里面的人会喜闻乐见,而且非常亲切的问你项目的有关内容或者助你填写调查问卷。不过后来小红包广告日渐失去吸引力,由于大伙的开心阈值提升了,而且重复的东西是不可能让用户持续高潮的,好似你xxoo的时候不可以一直用一个体位一样。因此对于服务号的摇一摇红包和关注红包,最少也有2元,而且还能分裂转变给你好友。2块钱是什么?官方的说法是一张彩票的价格,一份期望,2元彩票长期已经在广大群众心理打造了一个阈值,一份期望的阈值,『万一达成呢?』这种心理。而且这种期望还能传递给其他人(分裂转变红包),何乐而不为呢?
(4)纯粹是一种祝福
有时是大家商品经理想太多了,人家可能只是把传统的红包以微信红包这种新颖的方法发出来而已。以前只有结婚的人才能发红包,目前可以全民发,我也可以给朋友带去一份祝福。不过包多少呢?这个非常叫人纠结,太少不体面;给『上层』的人发红包,人家阈值高,太多支付不起。于是就有了
1.2 用户为何要抢红包?
(1)好玩刺激
这个理由还是留给那些无聊的人,不讲解,跟『为何要发红包?』的第一点差不多。那个,就刺激了大家玩红包接龙(不是某宝那个坑爹的红包接龙…)
(2)贪婪——人类原始的欲望
在法律和道德重重的压制下,深深地掩盖了人的本性,当有这种合法而且又光明正大的"抢钱",即便是0.01,也足以叫人们压制的贪欲井喷,造就了微信红包的兴盛。虽然官方说,摇红包是为了让老一辈知道大家的世界,知道大家的生活,让大家春节回家能一块摇红包。可是从朋友圈,从新闻,大伙在群里的反应,我一点都没感觉到红包让家人团聚在一块,不了解那是不是是公关说辞,这里不作评价,而对人性的激起确是彻彻底底的。正如所有些自然科学最后都会回归到哲学问题上,所有些商品也终究要回归到对人性的考虑上。(废话说太多了~~~)
(3)炫耀
证明自己单身20年,哦!不对,应该是证明自己手速快(不都是一个意思嘛,废话真多!)有些人无聊到自己发自己抢,以此在炫耀我们的4G互联网、光纤还有…麒麟臂。
(4)降低损失
不少人发了拼手气红包感觉自己钱包大出血,于是自己又抢了一把,期望自己抢到大一点的金额,等于发少一点红包。
1.3 为何要晒红包?
(1)炫富心理——我发出的红包统计页面
(2)攀比心理——红包结果页面
这里就不多作讲解了,想想你为何喜欢在朋友圈发东西就懂了。
2 入口
1
入口主要分为两大类:聊天窗口和微信钱包。
2
2.1钱包
在钱包添加红包入口,是由于用户初次用时,一般是先收到其他人的红包,自己要取钱,那样去什么地方取呢?一定是钱包,钱包需要集合所有跟钱有关的定义,给用户一个深刻的印象,像OmniFocis的透视功能(不了解不再计较…),需要把有关内容聚合到一个入口。所以钱包聚合了和钱有关的内容,譬如信用卡还款、手机充值、投资理财通等,用户首次进去收钱的时候,自然就看到微信红包并进一步引导用户绑定信用卡和发红包。另外假如用户首次用红包不是收到其他人红包,而是听说有红包这一功能或者看到其他人发红包,他第一会想到钱有关的东西应该在红包里面。
3
2.2 聊天窗口
而这聊天窗口中加入红包入口则是愈加简单暴力,用户在春节或者平时用会常常点开"+"发送图片,这就比较容易会见到红包入口了,而且微信在春节的时候特意把红包按钮用红色高亮显示了,这就愈加容易被用户发现,从而提升入口转换率。这里还有个逻辑,在单聊和群聊所进入的红包页面的不一样的,如下图所示:
4
群红包默觉得拼手气群红包而不是定额红包,为何要酱紫呢?先看看拼手气群红包的优势:
1、金额随机,时大时小的金额能给用户惊喜;
2、可以看到其他用户抢了多少,引起攀比心理(这次抢得不爽,下次必须要抢个大大哒);
3、产生不少新奇玩法,譬如手气最好的发3倍金额;
4、因为可以看到哪个抢了红包,所以群里面一直抢第一又不参与游戏的人基本上是用外挂软件,群成员自发的需要群主踢掉这个人,这种众包式的"反外挂"比微信自己用技术方法去解决愈加节省本钱和愈加有效。
至于拼手气群红包相对于普通红包的劣势就是需要很多的计算资源去计算红包的随机金额,不过对于腾讯那样厉害的构造师和财力,这类计算资源算不了什么,反而消耗这类资源去拉起微信群的活跃度和拉高同时在线人数让财报好看点愈加合算。
2.3 摇一摇
微信在新年前还额外的增加了摇一摇的红包入口,给一直被觉得"约炮利器"的摇一摇洗白(哈哈,开玩笑啦!)。加速度传感器也非常具备互动性,却一直隐藏在手机里面,用率不如摄像头和话筒。摇一摇红包非常不错的借助了每一个人手机里面"雪藏"的硬件。在"红包一定是要发的"和"摇一摇功能的代码本来就有"的两大首要条件下,增加摇一摇红包这功能并不会增加多少开发量和本钱,由于既然红包要发,无论用什么形式发,后台的负载均衡和高并发分流是一定要做的,摇一摇的代码在约pao的年代就已经非常健全了基本上不需要改,接入红包的逻辑就能了,所以机会本钱非常低。那为何必须要发红包呢?由于上一年已经带坏头了,示范效应致使支付宝也来分一杯羹,微信能不发吗?
3 界面
3.1发红包页面
在单人聊天窗口进入的普通(定向)红包的页面仅需输入红包金额和祝福语,点击,假如已经绑定银行卡,则调起对话框浮层;假如未绑定银行卡则跳转到零钱支付页面,点击按钮即可,不需要输入密码,在这个过程中,假如零钱不足,则会跳转到输入银行卡号的页面,点击之后需要接着输入名字、银行预留手机号和短信验证码,填写完成后即可用银行卡支付。
5
这里不能不提的是一个很人性化的设计,当点击"改完普通红包",从群手气红包切换到普通红包的过程中,已经输入的内容不会丢失,红包个数不变,此时的单个金额EditView(AndroidUI控件)中的值会由 总金额/红包个数 得出并自动填充;当点击"改为群手气红包",从普通红包切换到群手气红包的过程中,已经输入的内容不会丢失,红包个数不变,此时的总金额EditView中的值会由 单个金额*红包个数 计算出并自动填充,,不需要用户重新输入,很贴心。这也是微信"将客户体验做到极致"的地方之一。
3.2红包『抢』页面
聊天窗口会显示出红包样式的聊天消息,点击红包后会出现拆的页面。
6
3.3红包『拆』页面
点击按钮之后,那坨黄色的东西会转(用几帧图片切换形成的动画,在IOS上比Android上运行起来愈加流畅),那坨东西转完之后页面会跳转到。值得一提的是Android最新版本中将Html版本的红包换成了Android原生红包界面,为何这么做呢?
一是微信惯用的牺牲推广客户端资源(CPU、内存、储存卡容量)去换取服务器端的稳定和降低资源投入的方案,页面资源放在当地,如此子web前端服务器容量就能降低投入,同时也可以降低推广客户端对资源服务器的访问量。类似的,微信的聊天记录是默认不存储在服务器端的,而是将各种图片语音短视频全部塞到你手机的内存里面,微信表情在6.0版本之前也是不保存到服务器的。
二是以往基于web的红包页面常常会出现"妈的页面还在loading红包就没了""红包来了却连不了网是如何一种体验"等等的用户抱怨,而原生的页面由于放在当地无需远程加载,仅需传输简单的红包ID,发送者等少量信息即可公告推广客户端显示红包页面,可以降低联网时间和减少互联网情况对抢红包的体验流畅度,让用户抢不到红包都不会感觉是由于微信没优化好,而是自己太幸福 (没单身的手速慢,哈哈)。下图为几种红包"拆"页面(大伙来玩找不一样,嘻嘻):
7
那这四个页面分别会在什么时间出现呢?在5.2中会做详细的介绍。
3.4红包结果页面
红包结果页面会显示抢到红包的人的列表,其中金额最大的为手气最好。当有两个或者以上金额相同的时候,以时间最早的一个为最好手气。页面还会显示发红包的人极其昵称、你一个人领到的金额(假如没领到就不会显示),零钱入口和转发该红包的入口、我的红包记录入口。红包结果页面也有非常多种,详见本文的5.3部分.
8
3.5摇一摇红包
9
摇一摇红包和企业红包的随机办法和群手气红包大同小异,因为没接触过企业红包的发放步骤,这里不多说。
为何要有剩余红包个数呢?
引用鹏飞在每人都是商品经理举办的商品经理大会广州站上说的一句话"给用户一个预期,目前还有没红包,还有多少,而且这个数字需要准确,不可以忽悠用户。有的朋友和我说,他们就是在最后几秒摇到的。所以,要让用户为期望而摇,为了期望,把手摇断,又算什么!"。没错,这个数字是"准确"的,但他并非实时的。由于过于频繁刷新的数字少量降低,不只用户没感知,不停的访问数据库剩余红包数对于服务器也是很大重压,所以推断微信是使用这种方案:每降低1个单位(譬如说50W)的红包数目,自动将这个值写入缓存服务器,用户摇红包的时候都直接访问缓存,而且不是每次摇都访问剩余数,而是摇n次之后(譬如摇了5次)才去请求一次剩余红包数,如此就把传递到服务器的重压降低n倍。
上图最后那个页面你没见过?
微信官方说,当服务器重压过大的时候,唤起让用户休息一下这个页面。这里我提出另外一种方案,或许微信也使用了这种方案:当用户摇一摇请求红包时,服务器重压过大,互联网阻塞或者队列已满等异常状况下,会直接公告推广客户端"你没抢到",也就是直接返回那个摇红包的页面进行下一次的摇一摇动作,如此子永远也不会显示那个"休息一下"的页面。
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,在这公司基础上再人为控制概率。
策略1、
人为干扰概率的,有人拿到京东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 a0.85:
_min = 2.00
_max = 5.00
elif a0.95a = 0.85:
_min = 5.00
_max = 20.00
elif a0.9999a = 0.95:
_min = 20.00
_max = 50.00
elif a0.9999:
_min = 618.00
_max = 618.00
random.uniform(min,max)
策略2、
_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 QA若干整理(这一部分是网上收拾的,不了解怎么样分类最好就放在一块了)
①既然在抢的时候有原子减了就不应该出现抢到了拆开没的状况?
这里的原子减并非真的意义上的原子操作,是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操作。另外还有一个对账来保障。
5交互
5.1前后端交互时序
(1)绑定银行卡
10
(2)收发群手气红包
11
① 发起红包操作
② 银行扣款逻辑,不成功则返回,成功则进行下一步
③ 请求将红包写入数据库某个set,并获得红包ID返回推广客户端
④ 长连接公告推广客户端成功
⑤ 其他用户接收到红包消息,点开,拆。因为用户操作的速度远远低于计算机处置速度,所以这打开和拆开的离别,等于设置了一道缓冲。另外,点开之后,不直接获得金额,而是先读取红包是不是领完的缓存,假如没领完则显示的按钮。点击之后第三访问缓存看红包是不是领完,假如没领完,则请求服务器内存计算随机金额并返回推广客户端,然后异步写入数据库。
⑥ 红包结果会写入LIstView(Android的UI控件名字,ios也有类似的控件)中,用户可以立刻看到
⑦ 当用户第三打开红包结果页面时,会从数据库读取最新的结果列表并更新结果列表。
(3)收发普通红包
① 发起红包操作
② 银行扣款逻辑,不成功则返回,成功则进行下一步
③ 选择发送对象(若在聊天窗口中发起着跳过这一步)
④ 计算红包均值(总额/个数),将红包个数和均值写入数据库,返回红包ID到推广客户端
⑤ 其他用户点开红包,拆,访问红包个数判断是不是大于0,若为TRUE,则个数减1;若为FALSE则公告推广客户端显示样式。
5.2 界面交互
5.2.1 具体流程
13
5.2.2 拆红包页面显示逻辑
对群手气红包、群普通红包、普通红包(其实就是红包个数为1的群普通红包)和是不是领到和是不是领完做3×3×3的交叉剖析之后,总结出以下结论:
mmexport1442151693886
5.2.3 红包结果页面显示逻辑
说明:
1 代表有出现该项
"字样"代表下图所示地区的文字内容:
16
"按钮"代表蓝色文字链接,如下图所示:
17
金额是指自己拿到的金额
18
抢到的人是指一个列表:
19
绿色格子代表没这种逻辑,可能是不出现该页面或者其他缘由。
对上表的数据进行挖掘,大家可以发现以下规则集:
(1)当领到红包的时候,会显示按钮"已存入零钱,可用于发红包"、"已存入零钱,可用于消费"、"已存入零钱,可用于转账"、"已存入零钱,可用于提现"的其中一个,顺序或随机出现;并显示自己所获得的红包金额。
(2)当自己发的红包没被领完,会显示按钮"继续发送此红包";
(3)领到其他人发的红包时,会显示按钮"查询我的红包记录";
(4)对于群手气红包被领完时,假如红包是自己发的会显示字样"n个红包共n元,n秒被抢光";若是让人发的红包则会显示字样"n个红包,n秒被抢光";对于(群)普通红包被领完时,会显示字样"n个红包共n元";
(5)对于红包(个数大于1)没被领完,我们的红包会显示字样"已领取x/y个,共x/y元";其他人发的红包字样"领取x/y个";
(6)对于红包(个数等于1)没领完时,会显示字样"红包金额n元,等待他们领取";
(7)对于群手气红包和自己发的普通红包都会显示抢到红包的人的列表;
(8)已经被领完的群手气红包才会显示"最好手气"的标识;
从(4)-(6)的规则大家可以看出,微信做到为何是一个出色的商品而不止是一个及格的商品。自己发的红包会显示出总金额,自己发了多少钱自己心里有数,却不期望其他人看到总的金额(虽然能依据列表算出来,但大多数人不会去计算每个其他人红包的总金额),防止发红包的用户还要承受"面子问题"挫伤用户发红包的积极性。如此去打造一种无分贵贱贫富,每人都可以发红包的环境,间接提升发红包的人数和整个平台的活跃度。
5.2.4摇一摇红包
这一部分由于写文章的时候摇一摇红包活动已经下线了,所以只能从网上找来截图,简略地说明一下步骤。如下图:
仅以此文,纪念大学四年为了加入微信团队所做出的努力。