首页 > 编程知识 正文

项目设计方案,现场抽红包活动方案

时间:2023-05-05 03:15:54 阅读:170933 作者:4057

这两天做了抢红包的功能。 这里整理一下实现方法。 一整天的两个难点是: 1、如何应对红包的高合并。 其实红包类似秒杀功能,如果一个红包一开始就全部被抢走,很可能撑不了一秒钟,所以性能不能有问题。 2、如何实现红包公平、红包相对公平,又能防止10个人抢10元红包? 第一个人直接夺走9.8,之后的人有可能分不充分。 所以在这里从这两个问题开始展开。

尽量公平地抢红包。 这主要是算法,比较单一,所以我先接下来。 基本上可以分为两种想法。 一种是在制作红包的时候,将m金额的红包分成n份保存,抢到的时候直接按照现在的顺序获取对应的插槽金额就可以了。 该算法的优点是从一开始就确定了每个人的金额,即使抢了后面的人也不能充分抢。 缺点是做红包很慢,需要存储空间来存储数据。

另一种思路是计算用户抢的时候抢了多少钱。 基于这一想法,如果能避免公平性和未被充分剥夺的情况,比第一种想法更好。 到目前为止我们看到了网上的很多资料,基本上是基于抢着发第二个钱的方式。 最多的是基于二分法。 例如,100人,10人的红包。 那应该是每人10元。 所以,第一个人的随机区间是1到20,平均可以抢10元。 假设第一个人真的抢了10元,剩下的90元和9人,平均每人还有10元,第二个随机区间也是1元到20元,所有人的数学期望实际上是10元,实现公平性。 然而,可能存在以下极端情况:

第一个区间是1-20,但幸运地抢了20元。 第二个人的平均值是80/9=8。 (这里希望下区整改,即使方便计算也不要超过最大金额),区间1-16元,抢了16元。 第三人的平均值为64/8=8,区间为1-16元,抢了16元。 第四人的平均值为48/7=6,区间为1-12元,抢了12元。 第五人的平均值为36/6=6,区间为1-12元,抢了12元。 第六人的平均值为24/5=4,区间为1-8元,抢了8元。 第七人的平均值为16/4=4,区间为1-8元,抢了8元。 第八人的平均值为8/3=2,区间为1-4元,抢了4元。 第九人的平均值是4/2=2,区间是1-4元,抢了4元。 这时,最后一个人没钱了,我们根据这个二分随机算法进行改版。 我会确保给每个人钱,对剩下的金额再进行二分钟随机取得。 如下所示。

第一个人,每10人留1元。 100-10=90元,对剩下的钱分成90/10=9元。 第一个区间是1-18元,如果此人幸运地抢了18元,连同最初剩下的1元一起抢了19元。 第二个人,红包一共还剩81元,每9个人还剩1元,81-9=72元,平均值72/9=8元,区间1-16元,抢16元,加上预约1元,一共17元。 第三个人,红包一共还剩64元,每8个人留1元,64-8=56元,平均值56/8=7元,区间1-14元,抢14元,加上预约1元,一共15元。 第四个人,红包一共还剩49元,七个人每人还剩1元,49-7=42元,平均值42/7=6元,区间1-12元,抢12元,再加上预约1元,一共13元。 第五个人,红包一共还剩36元,每6个人留1元,36-6=30元,平均值30/6=5元,区间1-10元,抢10元,再加上预约1元,一共11元。 第六个人,红包一共还剩25元,5个人各留1元,25-5=20元,平均值20/5=4元,区间1-8元,抢8元,加上预约1元,一共9元。 第七个人,红包一共还剩16元,每4个人留1元,16-4=12元,平均值12/4=3元,区间1-6元,抢6元,加上预约1元,一共7元。 第八个人,红包一共还剩9元,每3个人留1元,9-3=6元,平均值6/3=2元,区间1-4元,抢4元,预留1元,一共5元。 第九个人,红包一共还剩4元,两人各留1元,4-2=2元,平均值2/2=1元,区间1-2元,抢2元,预留1元,一共3元。 第十个人,红包一共剩下一元,最后一个人获得了一元。 这样,最后一个人就不能夺走了,同时在数学上也保证了公平性。

高合并前所述的抢红包类似秒杀场景,需要一定的性能保证,同时要保证红包不会像10个红包一样出问题。 如果合并不顺利,抢了20个红包,会失去血。 由于这两个原因,在传统数据库的基础上扣减红包会带来很大的压力。 另外,如果我们实现数据库的悲观锁定,可能会造成交通堵塞,如果实现乐观锁定,容易引起大量的失败要求,影响用户体验。 因此最终决定基于redis实现。 redis的lua脚本本身具有原子性,不会同时处理多个抢现金事件,redis自身的高性能(秒级10w )操作量也能很好地接受这个秒杀场景。

决定了基本的算法和设计方案之后,再推敲细节。 redis的高性能多亏了小操作。 也就是说,无法将大周期这样费时的操作放入redis中。 它产生了极其严重的影响,也有可能堵塞与redis相关的所有业务。 所以这里只把红包的扣除操作放入redis,设计如下。

当用户发出红包时,红包的剩余个数和剩余金额,即总个数和总额将被写入redis,此次发出的红包的所有详细内容将被记录在数据库中。 在数据库操作之前,在redis操作之后,会向整个数据写入方法添加事务,以确保数据写入的一致性。 用户夺取红包时,在服务器端生成[ 0,1 ]的浮点随机数,并带入redis的lua脚本中。 在脚本中实现了前一个抢红包的算法,根据当前剩余红包的个数和剩余金额,计算出当前用户的

红包区间,再将红包区间和我们带入的[0,1]的浮点随机数相乘并向下取整得到当前用户抢到的金额数,再对redis里的剩余个数和剩余金额进行修改。从lua脚本执行结果中获取到剩余数量,剩余金额,本次抢到的金额,然后发布mq,将本次抢红包的日志记录和金额修改的操作放到异步去进行,如果mq发送失败,需要手动回滚调redis,将剩余数量自增1,将本次抢到金额也要加回剩余金额。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。