Java实现发红包、抢红包的个人思考
公司App最近需要新增一个房间内发红包、抢红包的功能,在这里记录一下自己的思考!
大致可以拆分为下面几个步骤:
1.发红包
2.抢红包
3.存红包
发红包
对于发红包,为了用户更好的体验,用户大致抢到的金额应该是差不多的,所以就需要一个算法来解决金额分配的问题,参考微信抢红包的架构设计,其中就用到了 二倍均值法来解决金额分配的问题,代码和测试用例如下:
拆分好之后该存到哪里呢?首先能想到的是存在mysql或者redis,由于mysql是千级并发量,所有不考虑mysql存储,如果用redis的话,五大数据类型应该采用哪一种数据类型更好呢?对于红包金额,首先排除掉set和zset,因为我们知道红包金额是可以重复的!再想想,对于一个 key 存多个value,list类型再合适不过了!
抢红包
用户抢红包得考虑一个问题,首先它是一个并发问题,那是否需要加锁呢?加锁又要加什么锁,同步锁还是分布式锁?有没有什么方法不用加锁就具备加锁的效果呢,满足原子性和一致性?redia天生骄傲,出生就带着,因为redis的命令本身具有原子性。因为我们的红包金额存在list里面,每次有人来点击抢红包,就从list里面lpop出去一个,直到抢完为止,并且给该红包key可以设置一个过期时间,因为大家都明白,红包24小时没有抢完是要回退的!
存红包
首先明白为什么要存红包?一是用来防止用户重复抢红包,二是发红包的人可以看到自己发的红包分别被哪些人抢到了多少钱!很容易想到存红包可以用hash来存储!
demo
/**
* 拆分+发送红包
http://localhost:5555/send?totalMoney=100&redPackageNumber=5
* @param totalMoney
* @param redPackageNumber
* @return
*/
@RequestMapping("/send")
public String sendRedPackage(int totalMoney,int redPackageNumber)
{
//1 拆红包,总金额拆分成多少个红包,每个小红包里面包多少钱
Integer[] splitRedPackages = splitRedPackage(totalMoney