会员登录APP或者小程序;
调度器查询要进行的活动种子;
数据反馈活动种子信息;
活动预热,根据奖品数据,生成奖品池令牌桶;
活动时间到,前台弹出红包雨,会员参与抽奖;
前端获取活动信息;
缓存返回活动信息给前端;
进行用户登录、资格等基础校验;
基础校验通过则获取令牌;
缓存返回获取到的令牌;
校验令牌有效性,是否在活动时间;
令牌检验失败则令牌放回队列;
令牌有效则说明中奖,组装中奖信息;
提示用户中奖;
异步通知消息服务中奖信息;
执行持久化操作,入库中奖信息;
k-v,以活动id为key,活动对象为value,永不超时
redisUtil.set(RedisKeys.INFO+game.getId(),game,‐1);
hset,以活动id为group,用户等级为key,策略值为valueredisUtil.hset(RedisKeys.MAXGOAL + game.getId(),r.getUserlevel()+"",r.getGoalTimes()); redisUtil.hset(RedisKeys.MAXENTER + game.getId(),r.getUserlevel()+"",r.getEnterTimes());
双端队列(不清楚的自行百度),以活动id为key,在活动时间段内,随机生成时间戳做令牌,有多少个奖品就生成多少个令牌。令牌即奖品发放的时间点。从小到大排序后从右侧入队。
redisUtil.rightPushAll(RedisKeys.TOKENS + game.getId(),tokenList);
k-v , 以活动id_令牌为key,奖品信息为value,会员获取到令牌后,如果令牌有效,则用令牌token值,来这里获取奖品详细信息
redisUtil.set(RedisKeys.TOKEN + game.getId() +"_"+token,productMap.get(cgp.getProductid()),expire);
假设活动时间间隔太短,奖品数量太多。那么极有可能产生的时间戳发生重复。
解决技巧:额外再附加一个随机因子。将 (时间戳 * 1000 + 3位随机数)作为令牌。抽奖时,将抽中的令牌/1000 ,还原真实的时间戳。
//活动持续时间(ms)
long duration = end ‐ start;
long rnd = start + new Random().nextInt((int)duration);
//为什么乘1000,再额外加一个随机数呢? ‐ 防止时间段奖品多时重复
long token = rnd * 1000 + new Random().nextInt(999);
k-v,以活动id_用户id作为key,中奖数为value,利用redis原子性,中奖后incr增加计数。
抽奖次数计数也是同样的道理
redisUtil.incr(RedisKeys.USERHIT+gameid+"_"+user.getId(),1);
抽奖时,从令牌桶左侧出队和当前时间比较,如果令牌时间戳小于等于当前时间,令牌有效,表示中奖。大于当前时间,则令牌无效,将令牌还回,从左侧压入队列。
阅读量:2136
点赞量:0
收藏量:0