红包设计与实现
背景
去年年底,接到一个红包的需求:在直播间发送一个红包/用户发送大礼物,系统会生成一个大红包,让在直播间内的人抢,红包可以是金额,也可以是礼物(鲜花,鼓掌等)。用户抢到 的金额或者礼物,需要入库保存。
先上红包随机算法实现代码,一起学习:https://download.csdn.net/download/weiwenhou/10606556
红包的设计
1.用户发送大礼物,后台根据大礼物的金额,生成红包总金额M以及总的红包个数N
2.尝试根据总金额M,根据要分配的个数,划分为N份。
3.金额,红包类型,红包个数保存到DB,生成红包ID
4.把尝试划分的N份小红包放进Redis队列(leftPush all)
5.用户请求抢红包/查看详情,如果已经抢完,过滤无效请求,放回查看详情的结果。
6.用户抢到的红包或者礼物,会异步更新到DB数据库。
流程图:
1.发红包流程图:
2.抢红包流程图:
难点
1.拆红包:
微信红包金额是拆的时候实时算出来的,采用的是纯内存计算,不需要预算空间存储;而我们的设计是预先分配好的,发完红包提前把它分配配好,生成小红包,虽然需要占存储,但是因为红包数量不会太大,并且可以减少了锁竞争,可以接通过Redis的原子操作api抢红包。
2.红包随机分配算法
总金额为M,分发N个红包,每个红包内的金额是0.01-(M/N*2)之前。
比如:发10块钱红包,总共10个红包,那么抢到的每个小红包金额在0.01元~2元之前波动。
在此附上我的分配算法代码(因为我们使用自己平台的货币,所以最小单位是0.1):
分配算法源码地址:https://download.csdn.net/download/weiwenhou/10606556
3.高并发读
1)应对高并发,通常是业务层拦截过滤无效缓存,但考虑到直播抢红包的人数不会太大,所以暂时不拦截。
2)对DAO层增加Redis以及CaffeineCache本地缓存减少数据库压力
3)利用Redis的setnx,以及lpop的原子操作,所以不会存在一个人抢多个红包,两个人同时抢到一个红包(除非Redis挂了)
4.对账
用户每抢一个红包,都会异步记录到DB数据库,生成的红包也会记录到DB,所以可以对账红包数据是否正常。
不足
1)redis挂的话,没用通过DB保障服务继续。
总结
目前直播红包功能上线八个多月,运行良好,没发现什么异常或者数据没对上的情况。