抽奖活动业务设计与思考

2,606 阅读5分钟

1.背景

在很多APP中,我们经常可以看到很多九宫格或者砸金蛋的抽奖活动,例如掘金的签到抽奖。

这个需求目的相对,主要是为了形成内部积分闭环,每日免费赠送一次抽奖机会不仅可以促进产品日活,让用户养成习惯(好的用户是靠养出来的),

用户打开app或者网页端,签到免费获得一次抽奖。

2.抽奖活动业务分析

这里以简单的举例进行业务分析,并不是以掘金抽奖具体业务分析:

  1. 动态展示奖品。
  2. 动态展示抽奖需要消耗的积分数。
  3. 展示当前剩余积分。
  4. 中奖记录分类展示,分为大奖和小奖,并已跑马灯形式展示。
  5. 每个奖品可以配置中奖权重,奖品个数。

如下图所示(来自deepin画图软件随便画了一下)

image.png

3.方案规划

  • 主要方案设计
    1. 抽奖活动系统与积分业务系统相关,单抽奖系统是相对独立的。
    2. 后台可以配置中奖奖品与权重,以及每个奖品个数。
    3. 保证抽奖奖品个数有限制的不可多送
  • 前端抽奖架构样例

image.png

当客户端访问活动抽奖系统时,查询出配置的奖品列表,用户可用积分,活动时间段及其他相关配置,抽奖页面跑马灯等。

在这里访问奖品列表以及跑马灯(抽奖记录日志数据)可以进行缓存处理,因为不涉及时效性问题,图上只需要在活动系统与数据库查询之间进行数据缓存。

  • 解决方案

如何保证抽奖奖品个数有限制的不可多送?其实这种问题如今已经很常见了,具体可以在网上可以寻找很多思路,我这里使用了中间件redis 进行标记奖品处理,第一是为了方便服务器水平扩展,第二不使用太多中间件(例如不涉及zk,以及消息队列等):我的做法是后台每次上奖品时候把奖品缓存进redis,进行预加载处理,利用redis inc 以及数据库的锁去保证库存问题。

image.png

当后台服务器通过修改奖品配置,例如奖品权重,去覆盖缓存中的抽奖数据,客户端最主要是和redis打交道,当用户中间,比如奖品类型是需要判断库存的,那么我们就通过数据比较,最后修改数据库,当数据库执行成功时候才认为用户中奖。当redis inc后的数值大于或者等于该奖品库存数量(当然,也可以再次抽奖时候该奖品不混入奖池中)。相信优秀的产品经理一定会考虑到程序猿会写bug,所以顺水推舟时候,会设计一个安慰奖作为抽奖意外,比如设计一个10积分,当某用户抽奖抽到了“大奖”,由于发大奖逻辑异常,这个时候就可以返回一个默认奖

  • 发奖逻辑方案

对于发奖,这个就很简单了,根据中奖类型,走不同的逻辑,典型的if...else if..,这里可以使用 策略模式 优化代码。

4.数据库设计

  • 活动配置表
字段数据类型描述
idbigint(19)主键
imagevarchar(512)活动大图
namevarchar(128)活动名称
start_timedatetime活动开始时间
end_timedatetime活动结束时间
consume_typevarchar(20)消耗类型(integral积分,jewel宝石)
consume_numbigint(19)消耗数量(单位个)
statustinyint(2)活动状态(1开启,2关闭)
create_timedatetime创建时间
create_uservarchar(20)创建用户
update_timedatetime修改时间
update_uservarchar(20)修改用户
is_deletetinyint(2)是否删除
  • 奖品表
字段数据类型描述
idbigint(19)主键
iconvarchar(512)奖品的icon
namevarchar(64)奖品名称
typetinyint(2)奖品类型(1积分,2会员,3实物大奖)
stock_countint(11)库存(单位个)
enable_stocktinyint(2)开启库存校验(0关闭,1开启)
weightdouble(2,4)奖品权重
activity_idbigInt(19)绑定活动的id
create_timedatetime创建时间
create_uservarchar(20)创建用户
update_timedatetime修改时间
update_uservarchar(20)修改用户
is_deletetinyint(2)是否删除
  • 抽奖日志表(哪个用户什么时间抽中了什么奖品)
字段数据类型描述
idbigint(19)主键
user_idbigint(19)用户id
prize_idbigint(19)奖品id
create_timedatetime创建时间
...

5.后台样例

image.png

6.尾言

大多数情况下,抽奖活动为了平衡产品内部 数据流水问题,比如积分,当用户积分过多,会造成积分的“通胀”,也就是没有花出去的地方,比如王者荣耀的钻石抽奖,就是为了平衡钻石,当大量的用户拥有过多的,而没有花出去的地方,这就导致了钻石特别不值钱,例如天天酷跑。在掘金中,设计一个每日签到抽奖的,每日签到作用是促进日活,签到和抽奖结合,也是促进日活的方案,可以增加APP的打开频次和网页的点击量(流量),并且容易养成一批忠实用户,接下来的日子里,掘金的兑换商店会做出来,钻石是产品内部唯一通用货币,送的钻石如此之多,我猜,屯钻石的用户应该会很快兑换到奖品,从而慢慢弱化抽奖,作为一个钻石消耗口,后面钻石可能不会有这么多出现。

​ 不想了,老实打代码吧,剩下的交个数据分析的人,我们只要正常造就行~(希望掘金不要揍我 ^_^ )