微信过期红包能看金额么(最全解密微信红包随机算法(含代码实现))

在编写本文内容时,我参考了网上的资料。有关详细信息,请参考“参考资料”部分。感谢分享者。

1、引言

本系列文章已经整理了10篇,但是没有一篇涉及到具体红包算法的实现,主要有以下两点原因。

一方面,社交/IM产品中的红包功能同质化严重,红包算法的可玩性是“核心竞争力所在”,这是同质化功能的差异化竞争思路,不会随便公开。

另一方面,市面上还有各种抢红包的插件。一旦这些算法公之于众,很可能这些插件开发者就会搞出一些幺蛾子。

所以在这种情况下,如果要做社交/IM产品中的红包功能,只能想办法实现红包的随机算法,很难找到大算法直接套用。

本着即时通讯网一贯的im知识传播的精神,收集和查阅了大量的网上资料,综合了比较可靠的信息来源,才有了这篇文章。本文根据有限的资料,分享了微信红包随机算法实现中的一些技术要点,整理出了两个比较靠谱的红包算法实现思路(包括可运行的实现代码),希望能给你的红包算法开发带来启发。

声明 : 本文信息整理自互联网,仅供学习研究之用。如有任何不妥,请通知杰克·江。

学习交流:

-移动IM开发入门:《初学者入门就够了:从零开始开发移动IM》

详细说明:开源IM框架源代码:https://github.com/JackJiang2011/MobileIMSDK

本文已发表于微信官方账号“即时通讯科技圈”。

2、系列文章

“解密社交软件红包技术(一):全面解密QQ红包的技术方案——架构、技术实现等。”

社交软件红包技术解密(二):微信摇一摇红包技术解密从0到1的进化

社交软件红包技术解密(三):微信摇一摇红包雨背后的技术细节。

《社交软件红包技术解密(四):微信红包系统如何应对高并发》

社交软件红包技术解密(五):微信红包系统如何实现高可用性

社交软件红包技术解密(六):微信红包系统存储层架构的演进实践

社交软件红包技术解密(七):支付宝红包海量高并发技术实践

社交软件红包技术解密(八):微博红包全解密技术方案

社交软件红包技术解密(九):谈设计、容灾、运维、架构等。手Q的春节红包

社交软件红包技术解密(十):2020年春节红包手Q客户端技术实践

社交软件红包解密(XI):最全的微信红包解密随机算法(含演示代码)(*本文)

3、微信红包算法要点汇总

这是目前唯一能找到的,有微信团队成员参与的关于微信红包算法技术点的讨论材料。分享2015年,微信红包上线几乎没多久。大概是当时微信技术团队的人没有超出这些技术的顾虑,所以做了有限的分享,资料很少。这次他们重新整理了一下,可以作为参考资料。以下是信息体。

来源:InfoQ的一个架构组的技术讨论,由朱玉华组织(个人博客:zhuyuhua.com(目前无法访问))

背景:原因是一个朋友在朋友圈咨询微信红包的结构,于是在微信团队成员的参与下,我(指“朱玉华”)整理了一下这次讨论的技术要点,也就是以下内容(以问答的形式)。

3.1、算法实现的技术要点

[1]问:微信的量什么时候算?

答:微信金额是在拆解时实时计算的,不是预分配的,是纯内存计算的,不需要存储在budget 空之间。

为什么要实时计算金额?原因是实时效率更高,预算效率低。预算还会占用额外的存储空间。因为红包只占一条记录,有效期只有几天,所以不需要大到空。即使压力高,卧式膨胀机也是。

[2]问:关于实时性能,为什么一点击就抢到红包?

答:2014年,红包一开就知道金额。有两种操作:一是抢量,然后转账。

2015年红包的拆抢是分开的,需要分两次点,所以会出现抢到红包,但是红包打开后被告知已经抢完的情况。进入第一页不代表抢到,只代表当时有红包。

[3]问:关于分发算法,如何计算红包里的金额?为什么红包金额相差很大?

A: 随机,额度在0.01和残差均值2之间。比如你发100元,一共10个红包,那么平均值就是10元,那么发出去的红包金额就是 0.01 [/]

当前面的3个红包一共收到40块钱,剩下的60块钱,一共收到7个红包,那么这个[/]

注:这里的算法是每抢一个,剩下的就再执行一次上面的算法(Tim先生也觉得上面的算法太复杂,不知道是基于什么样的考虑)。

这样一开始就会超过总额,所以如果最后不够,就采用下面的算法:保证剩下的用户能拿到最低1分钱。

如果前面的人倒霉,那么后面余额越多,红包额度越多,所以实际概率是一样的。

[4]问:红包的设计

答:微信从财付通拉取金额数据,将生成的数字/红包类型/金额放入redis集群。app端将对红包ID的请求放入请求队列,如果发现红包数量超过,则直接返回。如果按照红包的逻辑处理成功获得令牌请求,财付通会进行一致调用。和比特币一样,交易记录是双面保存的,交易后会提交给第三方服务审核。交易过程中如有不一致,将被强制退货。

[5]问:并发处理:红包是如何计算和抢到的?

A:缓存会抵制无效请求,过滤掉无效请求。其实真正进入后台的量并不大。缓存记录红包数量,原子操作数量减少,0表示已经抢到。财付通是按照每秒 20万笔交易来编制的,但实际不到每秒 8万笔交易

[6]问:我怎样才能保持每秒8w的写作速度?

答:多主分片,卧式膨胀机。

[7]问:数据容量是多少?

答:一个红包只占用一条记录,有效期只有几天,不需要太多空小时。

[8]问:查询红包发放情况压力大吗?

答:抢到红包的人数和抢到的红包都在一个缓存记录里,没有太大的查询压力。

[9]问:一个红包一个队列?

答:没有排队,一个红包,一个带counter字段的数据。

[10]问:有没有数据证明每个红包的概率是否相等?

答:要么绝对平等,要么就是简单的拍脑袋算法。

[11]问:拍脑袋算法中会有两个最优解吗?

A: 会有一样的量,但是运气最好的只有一个,第一个最好。

[12]问:每次收到红包都会更新自己的数据吗?

答:每次抢到红包,cas都会更新剩余金额和红包数量。

[13]问:红包怎么入库?

答:数据库将累计已经收集的数量和金额,并插入收集记录。记账是后台异步操作。

[14]问:如果条目有错误怎么办?比如红包数量没了,余额还在?

答:最后会有一个通吃操作。还有一个调和要保证。

[15]问:既然抢的过程中有原子的减少,应该不会出现抢开的情况吧?

答:这里的原子减法并不是真正的原子操作,而是缓存层提供的CAS,通过对比版本号不断尝试。

[16]问:如果缓存和db失败了怎么办?

A: 主备+对账。

[17]问:为什么要把抢和拆分开?

答:总体思路是设置多层过滤器,层层筛选,层层降低流量和压力。

这样设计本来是因为抓取操作是业务层面,拆解操作是账号录入操作,一次操作太重,中断率高。从接口层面来说,第一个接口是纯缓存操作,制压能力强。一个简单的查询缓存屏蔽了大部分用户,做了第一道过滤,所以大部分人会看到已经抢完的提示。

[18]问:抢到红包后,你有什么发红包或者提现的策略吗?

答:大额优先入账策略。

鉴于以上技术点,有人还画了示意图(这是网上能找到的比较清晰的版本):



3.2、微信抢红包的过程模拟

根据上一节整理的信息,当有人在微信群里发一个N人的红包,总金额为M元时,后台大概的技术逻辑如下。

3.2.1)红包后台操作:

1)在数据库中添加一条红包记录,保存在CKV,设置过期时间;

2)在缓存中添加一条记录(可能是腾讯内部的kv数据库,基于内存,带落地,内核模式的网络处理模块,以内核模块的形式提供服务),存储抢红包人数n。

3.2.2)抢红包后台操作:

1)红包抓取分为抓取和拆解:抓取操作在缓存层完成,通过原子减法操作递减红包个数。当达到0时,表示已经被抢了。最后,后台实际的反汇编操作量并不大,通过操作的分离,将无效请求直接阻挡在缓存层之外。

这里的原子减法操作并不是真正的原子减法操作,而是其缓存层提供的CAS。通过对比版本号,存在一定程度的冲突,有冲突的用户会让他们去进行下一步的反汇编操作,这也解释了为什么有的用户抢到反汇编后发现已经收集完了。

2)在数据库中打开红包完成:通过数据库的交易操作累计已经领取的数量和金额,插入一个领取流程,入账是异步的,这也解释了为什么春节期间红包领取后余额中看不到。

拆解时,会实时计算数量。该数量是范围从剩余平均值的1到2倍的随机数。一个总金额为M元的红包,最大红包为M * 2 /N(且不超过M),拆完红包后会更新剩余金额和数量。财付通准备按照每秒20万笔交易记账,但实际只有每秒8万笔交易。

4、微信红包算法模拟实现1(含代码)

根据上一节微信红包随机算法的技术点,实现了一个算法,以下供参考。(注:本节内容引自《微信红包随机算法初探》一文)

4.1、算法约定

算法很简单。像微信的算法,不是提前算好的,而是抢红包的时候算好的。

量是随机的,极限在0.01和残差均值*2之间。(见上一节“关于分配算法,如何计算红包里的金额?为什么红包金额相差很大?”内容)

4.2、代码实现

算法的逻辑主要是:

public static double getRandomMoney(red package _ red package){

//剩余红包数量

// remainMoney剩余的钱

if(_redPackage.remainSize == 1) {

_ red package . remainsize-;

return(double)math . round(_ red package . remainmoney * 100)/100;

}

random r = new random();

double min = 0.01//

double max = _ red package . remain money/_ red package . remain size * 2;

double money = r . next double()* max;

钱=钱& lt= min?0.01:钱;

money = math . floor(money * 100)/100;

_ red package . remainsize-;

_ red package . remainmoney-= money;

还钱;

}

LeftMoneyPackage数据结构如下:

类别RedPackage {

int remainSize

双倍剩余货币;

}

测试过程中与初始化相关的数据有:

静态void init() {

redPackage.remainSize = 30

red package . remain money = 500;

}

附件是一个完整的Java代码文件,可以运行:

(附件无法上传。如果需要,请从这个链接下载:http://www.52im.net/thread-3125-1-1.html)

4.3、测试结果4.3.1 单次测试

根据上面代码中的初始化数据(30人抢500块),执行了两次,结果如下:

//第一次

15.69 21.18 24.11 30.85 0.74 20.85 2.96 13.43 11.12 24.87 1.86 19.62 5.97 29.33 3.05 26.94 18.69 34.47 9.4 29.83 5.17 24.67 17.09 29.96 6.77 5.79 0.34 23.89 40.44 0.92

//第二次

10.44 18.01 17.01 21.07 11.87 4.78 30.14 32.05 16.68 20.34 12.94 27.98 9.31 17.97 12.93 28.75 12.1 12.77 7.54 10.87 4.16 25.36 26.89 5.73 11.59 23.91 17.77 15.85 23.42 9.77

第一个随机红包的数据图表如下:



▲ x轴是抓取的顺序,Y轴是抓取的量。

第二次随机红包的数据图表如下:



▲ x轴是抓取的顺序,Y轴是抓取的量。

4.3.2 多次均值

200次重复的平均值:



▲X轴是抓取的顺序,Y轴是这次抓取量的概率平均值。

2000次重复的平均值:



▲X轴是抓取的顺序,Y轴是这次抓取量的概率平均值。

从上面两个图的平均结果可以看出,这个算法每次能抢到的量的概率几乎相等,从随机性上来说是合理的。

5、微信红包算法模拟实现2(含代码)

我对随机算法很感兴趣,恰好最近的研究方向有点偏随机数,所以我也自己实现了微信的红包分发算法(算法要点参考本文第三节)。(注:此段引自《微信红包算法分析》一文)

5.1、代码实现

从第三节我们可以知道,微信并不是一开始就预分配所有的红包金额,而是在拆解的时候进行计算。这具有高效性和实时性的优点。在这段代码中,红包是如何计算的?请参考第四节“关于分配算法,如何计算红包里的金额”。为什么红包金额相差很大?" .

那么基于这个思路,我们可以写一个红包分配算法:

/**

*不完善的红包算法

*/

公共静态双rand(double money,int people,List & ltDouble & gtl) {

if(people == 1) {

双红= Math.round(钱* 100)/100.0;

l.add(红色);

return0

}

random random = new random();

double min = 0.01

双max =钱/人* 2.0;

double red = random . next double()* max;

red = red & lt= min?min:红色;

red = math . floor(red * 100)/100.0;

l.add(红色);

double remain = math . round((money-red)* 100)/100.0;

返回保持;

}

算法的整体思路很简单,关注最后一个人就行了。这时候我们不计算随机数,直接用剩余的金额当红包。

5.2、第一次分析

利用上述算法,我们可以分析用户的抢红包行为。这里的模仿行为是:30元的红包被10个人抢。操作100次。

可以得到以下结果:



▲X轴是抓取的顺序,Y轴是这次抓取的量。

从上图不难看出,后抢的人风险更大,收益更大,获得“好运”的几率更大。

微信红包过期了能看金额吗

红包的面值分布是怎样的?



▲X轴为抓取顺序,Y轴为抓取量重复100次后的平均值。

从上图可以看出,都接近平均水平(3元)。

重复1000次呢?



▲X轴为抓取顺序,Y轴为抓取量重复1000次后的平均值。

近一点。。。

可以看出,这个算法可以让大家在概率上抢到大致相等的红包面额。

5.3、不足之处

有人提出了这个问题:



然后他放了几张他实验的截图。我在这里拍了一张。有兴趣可以去知乎的问题看更多图片。



这时候我哥们在和我的讨论中也告诉我,有一定的规律,可能会让最后一个抢匪有一些微小的优势,比如多0.01。

比如你发六个包,总金额0.09,最后一个被抢的概率是0.03。



但是,我之前的代码无法体现这一点。

比如10个人拆包 一袋0.11元,我的结果是:



可见上面的代码还是有缺点的。

所以我有个猜测:

微信可能不会随机计算总额。它可能在发红包之前就已经处理好了金额,比如提前减去(红包个数*0.01),然后在每个红包的随机值上加0.01,保证每个红包的最小值是0.01。

这个猜测可能会解决朋友和我哥们的疑惑。

5.4、完善算法

基于原始代码的简单修正:

公共静态双rand(double money,int people,List & ltDouble & gtl) {

if(people == 1) {

双红= Math.round(钱* 100)/100.0;

l.add(红色+0.01);

返回0;

}

random random = new random();

double min = 0;

双max =钱/人* 2.0;

double red = random . next double()* max;

red = red & lt= min?min:红色;

red = math . floor(red * 100)/100.0;

l.add(红色+0.01);

double remain = math . round((money-red)* 100)/100.0;

返回保持;

}

在这个算法中,第一次调用传入的钱的值是总额减去红包数*0.01,看起来是这样的:

_ money = _ money-people * 0.01;

5.5、第二次分析5.5.1 验证上次的不足之处

1)10人抢包0.11元:



2)两人抢包0.03元:



3)六个人抢0.09包:



5.5.2 修改后的代码会不会对已知结论造成影响?

30元的红包被10个人抢了,操作了100次。



▲X轴是抓取的顺序,Y轴是这次抓取的量。



▲X轴为抓取顺序,Y轴为抓取量重复100次后的平均值。

从上面两个图可以看出结论基本不变。

5.6、结论

通过上面的代码练习,我们知道:

1)先抢后抢,金额期望相同;

2)微信的红包算法很可能是提前给每人0.01的“底额”;

3)后抢者风险高,收益大。

5.7、补充

考的最后几张图,补充一下前面的观点,发n个红包,总金额是(n+1)*0.01,最后一个肯定运气最好。





你也可以试试。

以上,大概可以证明微信红包是每个人0.01的最低金额才分发!

6、参考资料

[1]微信红包随机算法初探

[2]微信红包算法分析

[3]微信红包架构设计简介

【4】微信红包的随机算法是如何实现的?

另外,在知乎上也有很多人参与了微信红包算法的讨论。有兴趣可以上去看看,或许会有更多启发:微信红包的随机算法是怎么实现的?》。

附录:更多微信相关资源[/s2/]

IM开发书:史上最全,微信各种功能参数和逻辑规则的总结。

微信本地数据库破解版(包括iOS和Android)仅供学习研究【附件下载】。

(本文同步发表于:http://www.52im.net/thread-3125-1-1.html)

您可以还会对下面的文章感兴趣

使用微信扫描二维码后

点击右上角发送给好友