微信、QQ是如何实现抢红包?

BigDecimal random = BigDecimal.valueOf(Math.random());

BigDecimal min   = BigDecimal.valueOf(0.01);

BigDecimal halfRemainSize = BigDecimal.valueOf(_redPackage.remainSize).divide(new BigDecimal(2), BigDecimal.ROUND_UP);

BigDecimal max1 = _redPackage.remainMoney.divide(halfRemainSize, BigDecimal.ROUND_DOWN);

BigDecimal minRemainAmount = min.multiply(BigDecimal.valueOf(_redPackage.remainSize - 1)).setScale(2, BigDecimal.ROUND_DOWN);

BigDecimal max2 = _redPackage.remainMoney.subtract(minRemainAmount);

BigDecimal max = (max1.compareTo(max2) < 0) ? max1 : max2;

BigDecimal money = random.multiply(max).setScale(2, BigDecimal.ROUND_DOWN);

money = money.compareTo(min) < 0 ? min: money;

_redPackage.remainSize–;

_redPackage.remainMoney = _redPackage.remainMoney.subtract(money).setScale(2, BigDecimal.ROUND_DOWN);;

return money;

}

运行结果

打印结果


(30人抢500块)数据模型如下:

重复执行1次结果

重复执行200次结果

重复执行2000次结果

微信抢红包架构介绍

Q1:微信的金额什么时候算?

答:微信金额是拆的时候实时算出来,不是预先分配的,采用的是纯内存计算,不需要预算空间存储。。

采取实时计算金额的考虑:预算需要占存储,实时效率很高,预算才效率低。

Q2:实时性:为什么明明抢到红包,点开后发现没有?

答:最开始2014年的红包一点开就知道金额,分两次操作,先抢到金额,然后再转账。

2015年之后的红包的拆和抢是分离的,需要点两次,因此会出现抢到红包了,但点开后告知红包已经被领完的状况。进入到第一个页面不代表抢到,只表示当时红包还有。

Q3:分配:红包里的金额怎么算?为什么出现各个红包金额相差很大?

答:随机,额度在0.01和剩余平均值_2之间。例如:发100块钱,总共10个红包,那么平均值是10块钱一个,那么发出来的红包的额度在0.01元~20元之间波动。当前面3个红包总共被领了40块钱时,剩下60块钱,总共7个红包,那么这7个红包的额度在:0.01~(60/7_2)=17.14之间。

注意:这里的算法是每被抢一个后,剩下的会再次执行上面的这样的算法。

这样算下去,会超过最开始的全部金额,因此到了最后面如果不够这么算,那么会采取如下算法:保证剩余用户能拿到最低1分钱即可。

如果前面的人手气不好,那么后面的余额越多,红包额度也就越多,因此实际概率一样的。

Q4:红包是如何设计的?

答:微信从财付通拉取金额数据郭莱,生成个数/红包类型/金额放到redis集群里,app端将红包ID的请求放入请求队列中,如果发现超过红包的个数,直接返回。根据红包的裸祭处理成功得到令牌请求,则由财付通进行一致性调用,通过像比特币一样,两边保存交易记录,交易后交给第三方服务审计,如果交易过程中出现不一致就强制回归。

Q5:并发性处理:红包如何计算被抢完?

答:cache会抵抗无效请求,将无效的请求过滤掉,实际进入到后台的量不大。cache记录红包个数,原子操作进行个数递减,到0表示被抢光。财付通按照20万笔每秒入账准备,但实际还不到8万每秒。

Q6:通如何保持8w每秒的写入?

答:多主sharding,水平扩展机器。

Q7:一个红包一个队列?

答:没有队列,一个红包一条数据,数据上有一个计数器字段。

Q8:有没有从数据上证明每个红包的概率是不是均等?

答:不是绝对均等,就是一个简单的拍脑袋算法。

Q9:拍脑袋算法,会不会出现两个最佳?

答:会出现金额一样的,但是手气最佳只有一个,先抢到的那个最佳。

Q10:每领一个红包就更新数据么?

答:每抢到一个红包,就cas更新剩余金额和红包个数。

Q11:红包如何入库入账?

数据库会累加已经领取的个数与金额,插入一条领取记录。入账则是后台异步操作。

Q12:入帐出错怎么办?比如红包个数没了,但余额还有?

答:最后会有一个take all操作。另外还有一个对账来保障。

Q13:数据容量多少?

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

Q14:查询红包分配,压力大不?

答:抢到红包的人数和红包都在一条cache记录上,没有太大的查询压力。

以来源于QCon某高可用架构群整理,整理朱玉华。

二倍均值法


算法原理:

剩余红包金额M,剩余人数N,那么:每次抢到金额=随机(0,M/N_2) 保证了每次随机金额的平均值是公平的 假设10人,红包金额100元 第一人:100/10_2=20,随机范围(0,20),平均可以抢到10元

第二人:90/9_2=20,随机范围(0,20),平均可以抢到10元 第三人:80/8_2=20,随机范围(0,20),平均可以抢到10元

以此类推,每次随机范围的均值是相等的

缺点:

除了最后一次,任何一次抢到的金额都不会超过人均金额的两倍,并不是任意的随机

代码实现

/**

* 二倍均值法

* @param totalAmount

* @param totalPeopleNum

* @return

*/

public static List divideRedPackage(Integer totalAmount,

Integer totalPeopleNum) {

List amountList = new ArrayList();

//为了使用random.nextInt(Integer)方法不得不先把红包金额放大100倍,最后在main函数里面再除以100

//这样就可以保证每个人抢到的金额都可以精确到小数点后两位

Integer restAmount = totalAmount * 100;

Integer restPeopleNum = totalPeopleNum;

Random random = new Random();

for (int i = 0; i < totalPeopleNum - 1; i++) {

// 随机范围:[1,剩余人均金额的两倍),左闭右开

int amount = random.nextInt(restAmount / restPeopleNum * 2 - 1) + 1;

restAmount -= amount;

restPeopleNum–;

amountList.add(amount);

}

amountList.add(restAmount);

return amountList;

}

运行结果

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

为什么我不完全主张自学?
平台上的大牛基本上都有很多年的工作经验了,你有没有想过之前行业的门槛是什么样的,现在行业门槛是什么样的?以前企业对于程序员能力要求没有这么高,甚至十多年前你只要会写个“Hello World”,你都可以入门这个行业,所以以前要入门是完全可以入门的。
②现在也有一些优秀的年轻大牛,他们或许也是自学成才,但是他们一定是具备优秀的学习能力,优秀的自我管理能力(时间管理,静心坚持等方面)以及善于发现问题并总结问题。
如果说你认为你的目标十分明确,能做到第②点所说的几个点,以目前的市场来看,你才真正的适合去自学。

除此之外,对于绝大部分人来说,报班一定是最好的一种快速成长的方式。但是有个问题,现在市场上的培训机构质量参差不齐,如果你没有找准一个好的培训班,完全是浪费精力,时间以及金钱,这个需要自己去甄别选择。

我个人建议线上比线下的性价比更高,线下培训价格基本上没2W是下不来的,线上教育现在比较成熟了,此次疫情期间,学生基本上都感受过线上的学习模式。相比线下而言,线上的优势以我的了解主要是以下几个方面:
①价格:线上的价格基本上是线下的一半;
②老师:相对而言线上教育的师资力量比线下更强大也更加丰富,资源更好协调;
③时间:学习时间相对而言更自由,不用裸辞学习,适合边学边工作,降低生活压力;
④课程:从课程内容来说,确实要比线下讲的更加深入。

应该学哪些技术才能达到企业的要求?(下图总结)

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
上的价格基本上是线下的一半;
②老师:相对而言线上教育的师资力量比线下更强大也更加丰富,资源更好协调;
③时间:学习时间相对而言更自由,不用裸辞学习,适合边学边工作,降低生活压力;
④课程:从课程内容来说,确实要比线下讲的更加深入。

应该学哪些技术才能达到企业的要求?(下图总结)

[外链图片转存中…(img-rOvYae0K-1712920738247)]

[外链图片转存中…(img-iMVQsfuv-1712920738247)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值