【开发经验】redis实现抽奖功能


前言

      抽奖的功能在互联网的项目中随处可见,通过这些给用户惊喜的功能,来达到引流的效果。但是这个功能说难也难,说简单也简单。因为一般互联网的工程都是集群部署,抽奖的时候还要考虑线程间奖品争夺的问题,通过redis可以很轻松实现抽奖功能,我阐述下我的思路,请大家参考。


一、抽奖功能要点

1.1、奖品多抽问题

      抽奖功能其实和商城是一样的,前面会有各种验证筛选,比如:黑名单过滤,地区用户过滤等等。
      最后剩下可以拿到奖品的几个用户,这几个用户都要在此通过数据库的数据来做最后一步的验证,避免出现出现奖品发多的问题。
实现思路:
      在该用户认定为可以拿奖的时候,这个奖品的库存肯定会有库存减1的操作。这个时候可以通过goods_num(库存字段)>1。如下:

update t_goods set goods_num=goods_num-1 where goods_id=#{id} and goods_num>1

      如此,update会返回修改行数,如果修改行数大于1时,可以认为库存成功,然后即可插入获奖记录信息。注意:要保证减库存和插入获奖记录是在一个事物中。

1.2、概率计算问题

      如果要自己计算概率逻辑,java代码通常会接触Random类进行随机值的计算。思路如下:
      随机一个0-100的数值,然后按照各个奖品的概率计算区间。0-20是一等奖;20-30是二等奖;50-100是三等奖。      按照这样的逻辑来处理,代码实现逻辑注意严谨,这个时候的数值非常重要。而且奖品池的大小也在越来越小。有时是概率抽奖,有时候是奖品池的逻辑,不过都可以按照这种思路处理。
在这里插入图片描述
      如上思路单机时或者简单的逻辑下只能自己实现,如果集群模式下概率的逻辑放到每个服务中可能会有问题。
例如:
      如果两个人都抽到了1等奖的最后一个奖品,这个时候肯定会有一个线程异常,如果是奖品池的逻辑的话,就需要再次计算这个线程应该获得哪个奖品。这种情况对于有顺序要求的场景是无法接受的。

二、redis实现抽奖

      Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。set集合中有两个指令非常适合在抽奖的场景使用。

  • SPOP key [count] 移除并返回集合中的一个随机元素。
  • SRANDMEMBER key [count] 返回集合中一个或多个随机数。

      如此,将所有的奖品通过SADD添加到SET集合中,然后通过随机命令获取对应的奖品即可。而且,抽奖一般是有时效性,正好可以配合redis的key的失效时间使用。使得抽奖功能很完美的解决。
      但是,好的东西肯定也会有其弊端,那就是redis的数据一致性。将奖品的信息放到了两个存储介质中储存,就有可能出现数据不一致的问题,一般数据会以关系型数据库为准。redis的要按照场景,在必要的步骤进行数据同步的判断,避免数据不一致导致的灾难。

猜你喜欢

转载自blog.csdn.net/qq_30285985/article/details/112322834