2)在Cache(可能是腾讯内部kv数据库,基于内存,有落地,有内核态网络处理模块,以内核模块形式提供服务))中增加一条记录,存储抢红包的人数N。
3.2.2)抢红包后台操作:
1)抢红包分为抢和拆:抢操作在Cache层完成,通过原子减操作进行红包数递减,到0就说明抢光了,最终实际进入后台拆操作的量不大,通过操作的分离将无效请求直接挡在Cache层外面。
这里的原子减操作并不是真正意义上的原子减操作,是其Cache层提供的CAS,通过比较版本号不断尝试,存在一定程度上的冲突,冲突的用户会放行,让其进入下一步拆的操作,这也解释了为啥有用户抢到了拆开发现领完了的情况。
2)拆红包在数据库完成:通过数据库的事务操作累加已经领取的个数和金额,插入一条领取流水,入账为异步操作,这也解释了为啥在春节期间红包领取后在余额中看不到。
拆的时候会实时计算金额,其金额为1分到剩余平均值2倍之间随机数,一个总金额为M元的红包,最大的红包为 M * 2 /N(且不会超过M),当拆了红包后会更新剩余金额和个数。财付通按20万笔每秒入账准备,实际只到8万每秒。
4、微信红包算法模拟实现1(含代码)根据上一节的微信红包随机算法技术要点资料,实现了一个算法,以下供参考。(注:本节内容引用自《微信红包随机算法初探》一文)
4.1、算法约定算法很简单,跟微信的算法一样,不是提前算好,而是抢红包时计算。
即:金额随机,额度在0.01和剩余平均值*2之间。(参见上一节的 “关于分配算法,红包里的金额怎么算?为什么出现各个红包金额相差很大?” 内容)
4.2、代码实现算法的逻辑主要是:
public static double getRandomMoney(RedPackage _redPackage) {
// remainSize 剩余的红包数量
// remainMoney 剩余的钱
if(_redPackage.remainSize == 1) {
_redPackage.remainSize–;
return (double) Math.round(_redPackage.remainMoney * 100) / 100;
}
Random r = newRandom();
double min = 0.01; //
double max = _redPackage.remainMoney / _redPackage.remainSize * 2;
double money = r.nextDouble() * max;
money = money <= min ? 0.01: money;
money = Math.floor(money * 100) / 100;
_redPackage.remainSize–;
_redPackage.remainMoney -= money;
return money;
}
LeftMoneyPackage数据结构如下:
class RedPackage {
int remainSize;
double remainMoney;
}
测试时初始化相关数据是:
static void init() {
redPackage.remainSize = 30;
redPackage.remainMoney = 500;
}
附件是可以运行的完整Java代码文件:
(无法上传附件,如有需要请从此链接处下载:)
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次的均值: