需求是这样的,后台可以配置大转盘活动的要素,主要的是空奖个数,空奖概率,各奖项的总数量,每日数量,中奖概率。除此之外还有参加的城市、客群、每人中奖上限等等,这个做好校验就行。
里面有两个需要注意的地方:一是如何按照概率中奖,二是各个奖项不能超中或少中。
如何按照概率中奖
后台有校验,奖项概率加起来满足100%。这里把奖项包括空奖合并起来,不必考虑顺序,给一个0到100的刻度,按照每个奖项的中奖概率,分配一个范围,然后才0到100中取随机数,落在哪个刻度段上,就是哪个奖。
如果概率是0.1%或者0.01%,可以把刻度上限给到1000或10000。如果概率加起来满足100%,那就把各奖项的概率除以概率的总和,根据这个概率进行抽奖。
各个奖项不能超中或少中
尤其在活动刚开始,用户都在抽奖,高并发的场景下,如何保证奖项不能超中或者少中。
- (防止频繁查库)前端加限制,防重复点击,N秒才能触发一次。
- (防止频繁查库)加redis分布式锁,key为用户id+活动id,N秒才能触发一次,没抢到锁,给用户返回操作太频繁。
- (防止频繁查库,超中)redis预热,每天首次查活动详情时,要给用户返回奖品信息,以活动id+奖品id+当天日期为key,每日数量为value,存到redis中,抽中奖项后,使用redis的原子操作decr减去数量,当返回的值小于0时,代表每日库存不足,返回空奖。
- (防止超中)扣减总库存时,增加乐观锁,update条件增加中奖数量小于等于总数量,返回条数小于1时,代表更新失败,返回空奖。
- (防止少中)用户中奖后,会优先在redis中减一,后面的更新总库存操作,插入抽奖记录操作等等,如有报错,或者业务校验等问题不能中奖时,需要把redis中的每日中奖数量incr加回来。