目录
1. 活动的配置
抢红包可以支持3种类型
- 固定的总金额,固定的红包数,每个红包金额随机,但总和必须等于总金额(总计100元,10个红包-二倍均值算法)
- 指定每一个红包的金额,以及红包个数(5个1元,6个2元,7个3元...)
- 指定总金额,以及单个红包金额的上下限(资金池100元,每个红包1-2元)
每个人可以抢的次数有以下两种情况
- 一人一次
- 一人多次
完成配置后
- 数据库中生成一条活动信息记录(活动id+活动开始时间+活动结束时间+每个人可抢次数),以及若干条红包信息记录(红包id+归属活动id+是否经redis处理标记位+归属人)
- 以活动id作为key,在redis中申请一个list作为队列,取20条红包信息记录使用lpush加入redis队列
- 以活动id+"info"作为key,在redis中申请一个hash,并把活动信息存入(活动id+活动开始时间+活动结束时间+每个人可抢次数)
2. 触发抢红包动作时,有4台机器并行处理抢红包业务
客户端发起请求(时间戳+用户手机号+参与活动id)
- 每台机器尝试获取redis的分布式锁,基于stringRedisTemplate.putIfAbsent,并设置超时时间为10s防止死锁
- 若每人只允许抢一次,可以考虑适用布隆过滤器
- 若每人允许抢多次,则:使用redisTemplate.opsForHash.putIfAbsent,key为活动id+“info”,field为用户手机号,value为用户可抢次数
- 若返回true,表示该用户还未抢过
- 使用lpop获取redis队列中的元素(红包id+红包信息)
- 使用redisTemplate.opsForHash.increment,key为活动id+“info”,field为用户手机号,delta为-1(用户剩余可抢次数-1)
- 直接返回客户端成功,并通过rocketMq异步发送手机号+红包id,更新数据库
- 若返回false,则说明该用户已经抢过一次,获取用户剩余可抢次数
- 若>0,说明该用户仍可以抢,重复3.1.1步骤
- 若<=0,说明该用户不可以抢了,直接返回客户端失败
- 若返回true,表示该用户还未抢过
- 使用llen判断redis中队列长度,若<10,则重新查询20条库表中redis处理标记位为空的记录,使用lpush加入redis队列
- 释放分布式锁