前文
因为临近年底了,项目大部分都快结束了,难得的开启了快乐的摸鱼时光,可是还没开始摸几天,老板就来了个任务:我们要搞活动,现在需要一个抽奖系统,你来搞一下。
好的,还没摸两条,又要开始干了,说干就干。
准备工作
这次的系统我用的是我最爱的nodeJs来完成,用到的框架也就是Koa2,其余的数据库的话,我用的是mySql,还有Redis,先来一份思维导图,捋清楚整个业务流程
大概奖品分为四种,一种是大奖(iphone12 pro max),还有小奖(苹果耳机),以及虚拟卷,还有一些支付代币,然后在抽奖之前,会对用户ID和IP地址进行今天的抽奖次数的相关验证,以及用户黑名单的验证,如果这个已经中过大奖的情况下,这个用户ID和IP地址则会被拉黑,接下来一段时间内的抽奖都将不会在中奖或者说只能中虚拟币这样的奖,最后,如果中奖的话,会有一个对于这个用户的中奖记录。
好了,貌似业务也不是特别复杂,so easy,项目初始化,model建起来,数据表创起来,搞起。
小试牛刀第一步
通过把基础的奖品什么的增删改查创建好,我大概说明一下我的奖品列表在刚开始创建的时候的样子,这里我就通过prize的model来展示它最初的样子。
然后在抽奖的时候,会先对有各种乱七八糟的验证,这里可以通过我的路由来说明整体的情况
这个大概就是业务的整体的一个流程走向,那么下面就是一个抽奖的环节了。
因为本菜鸡算法水平有限,网上那些抽奖算法实在是看不懂,就用了最简单粗暴的方式,通过生成随机数的方式来进行匹配。
首先我是通过随机数生成一个四位数的随机数,用来匹配奖品的中奖概率,如果生成的随机数小于所设置的奖品中奖概率则会中奖,否则就不中奖,如果在抽奖过程中触发了上面的某一个拦截器,那么就也是谢谢参与的了。
当然,如果你真的一个不小心抽中了我们的超级大奖,你就会被拉入黑名单,之后的抽奖里面不论你怎么抽,都会是一个谢谢参与送给您。
正式开始
抽奖奖品的设计
首先因为这个抽奖是在特定的时间点限时开始的,所以为了可以让我们的会员大老爷们可以有个更好的体验,这里我是在创建活动的抽奖商品的时候,同时把抽奖商品的信息缓存到redis里面,因为抽奖商品总的就只有四个,所以可以直接把它们打包成一个数组,然后将这个数组转换成字符串的形式存储起来,之后需要的时候,再把他重新转换回来就可以了。
同时这样设计的一个好处就是,当奖品的一些数据发生改变的时候,直接删除这个key就完事了,因为对于redis来说,去更改数据相当于删除在重新创建数据,开销上会大很多。
接下来,在抽奖的过程中,用户会先去读取缓存上面的奖品,如果缓存上面没有的话,就会去数据库里面找,然后把找到的数据再给它存到redis里面去。
注意一个小细节
因为抽奖的概率都是随机的,虽然说大奖的中奖概率非常的低,但也会有可能说在某一个时间节点上,突然很多人中了大奖,然后把大奖一次性给抽空了,所以为了避免这种情况的出现,我们需要有一个在抽奖时间内的一个发奖计划。
例如,在一天可以分成24小时,奖品分成很多个等分,在热点时间,像是晚上八点这样的时间就发出去多点,具体实现我是这样的
先设置一份记录
然后就开始进行发奖计划的重置
这样就可以避免出现突然在某一个时段把奖品给抽空了,造成后续的参与者没办法获得奖品的情况出现了。
用户抽奖次数,ip抽奖次数的限制,用户黑名单和ip黑名单
这里是为了防止某些人恶意刷抽奖的情况出现,如果一个用户已经达到了一定的抽奖次数,那么也就不允许这个用户再抽奖了,那么ip黑名单则是为了避免某一个ip地址下,通过申请不同的用户来参与抽奖。
同时ip黑名单和用户黑名单的作用上面也就提到了,如果是如果这个用户已经中奖了,则同时把这个用户和这个用户下的ip都一起拉黑,之后的抽奖过程中,如果他还继续抽奖,则给个虚拟币或者是谢谢参与给他。
开始抽奖
这里我的逻辑非常的简单,就是生成一个随机数,然后去匹配中奖区间,中了哪个就是哪个。
这里所有的数据,我都是通过ctx的上下文,然后根据koa2的洋葱模型的方式,传递给下一个中间件。
发奖
中了奖,那么就需要有一个发奖的过程,这里我是设置了一个奖品池,用户从奖品池里面去抽取奖品,也就是把所有的奖品的个数,放到奖品池里面去,然后把奖品数通过redis缓存起来,这样在发奖的时候,就不用直接的去操作数据库,而是可以通过使用redis中的Incrby命令来完成相关的操作,当完成了相关的数据扣款之后,在通过异步任务的方式,来对数据库进行数据的同步,从而保持数据的一致性。
当然如果抽中了奖品,但是该奖品已经没有库存了,那么也是属于没有中奖。
大概的实现思路是这样的
还有一点需要注意的,就是在往奖品池里面放入奖品的时候,最好是加一个分布式锁,从而来控制只有一个服务去初始化我们的库存数据。
最后
实际开发工作中,类似的业务,肯定还会有更多的考量,本菜只是写了一个有点类似于demo级别的东西,提供了一个思路,如果有哪里写的不好的地方,欢迎各位老哥执正。
领取专属 10元无门槛券
私享最新 技术干货