话不多说,直接上需求描述:

最近需要上一期活动,这个活动是以转盘抽奖为形式的抽奖活动,要求每个用户用积分进行抽奖,且中奖率为100%即不可出现不中任何奖品的情况,之后,又加了一个要求,即不能实行纯随机的抽取,如果如此会产生一个极端情况,如果开始的时候活动极其火爆由于随机的不可控性头一天用户便将所有优质奖品全部抽走,那么后来的用户将只会抽到保底奖品。

那么奖品就需要按时间分布在从活动开始到结束的时间段,其次需要做的是,在某些特殊的时间段,我们希望多投放一些奖品给用户抽到。

需求分析:

那么开奖策略可以为为每个奖品设置开奖时间,只有在开奖后来抽奖才能抽到该奖品,否则视为未中奖发保底奖品,我们只需要拿当前时间与最接近奖品开奖时间对比即可。

由上需求,那么就需要一个容器来存放这些奖品,对这个容器的要求:

1. 它可以以时间轴为维度取出奖品;

2. 它可以以时间轴为维度放入奖品;

3.它可以以时间轴为维度将奖品排序;

同时,后台应该有地方配置每个小时应投放的奖品数量,同时为保证配置数据能及时生效,应当是每小时前去向奖品池投放下一个小时的奖品;

如下图所示,每个奖品都有对应开奖时间,奖品1只有10000毫秒之后的请求才可以抽到,且只有奖品1抽走之后才可以抽奖品2;

抽奖步骤:

性能安全考虑:

显然,抽奖是容易引发并发问题的场景,高并发情况往往会带来两个问题

1. 超发问题,例如将10个奖品发给了11个人,用锁可解决;

2.数据库等基础组件负载过高导致宕机,以数据库为例,如果每个用户每抽走一个奖品都去连接数据库更新库存,数据库很有可能承受不住(数据库能承受的qps远不如redis);

方案:

使用redis的zset数据结构,这里简单说明下zset,它是一个基于跳表实现的有序集合,尤其适合排序场景比较多的场景,是一个典型的用空间换取时间的数据结构。这里我们用开奖时间戳作为score,保证其按照时间排序,存入的时候可以直接将奖品ID与时间戳存入其中即可。

同时设置定时任务,每个小时去拿下一个小时的所需的奖品,随机将其散列在下一个小时的各个时间上,并在此时就将各个奖品库存扣除。

ok,需求完美解决,锁的问题直接上代码,锁就是保证zset的排序操作与移除操作是原子操作,否则便会出现超发,使用了redis的setNx做分布式锁。

/*** 抽奖

*

*@paramturnTableNum 转盘编号

*@return奖品ID*/

public long getLotteryResult(long userId, intturnTableNum,

MapgoodsConfigMap) {

Set prizeSet = null;

String prizeResStr= null;try{if(RedisUtils

.lock(RedisKey.TURNTABLE_PRIZE_QUEUE_LOCK, String.valueOf(turnTableNum))) {

Set prizeSet=RedisClusterAccessor

.zrangeByScore(RedisKey.TURNTABLE_PRIZE_QUEUE, String.valueOf(turnTableNum),0, System.currentTimeMillis(), 0,1);if (null !=prizeResStr) {//在奖池中移除奖品

log.debug("{} remove prize {} {}", XGameContextHolder.get(), turnTableNum,

prizeResStr);

RedisClusterAccessor

.zrem(RedisKey.TURNTABLE_PRIZE_QUEUE, String.valueOf(turnTableNum),

prizeResStr);

}

}

}catch(Exception e) {throwe;

}finally{

RedisUtils.unlock(RedisKey.TURNTABLE_PRIZE_QUEUE_LOCK, String.valueOf(turnTableNum));

}if (null ==prizeResStr) {return -1;

}return CommonUtil.safeParseLong(prizeResStr.split("_")[0]);

}

redis实现抽奖php,使用redis zset实现抽奖,奖池商品按时间随机分布相关推荐

  1. 线上redis一般安在linux_redis的zset有多牛?请把耳朵递过来

    原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处. 本篇文章很短,但信息量很大,是关于redis的zset.我来分享一点遇到过的线上数据,或许对你的决策有帮助. redis支 ...

  2. Redis 为什么这么快? Redis 的有序集合 zset 的底层实现原理是什么? —— 跳跃表 skiplist

    Redis有序集合 zset 的底层实现--跳跃表skiplist Redis简介 Redis是一个开源的内存中的数据结构存储系统,它可以用作:数据库.缓存和消息中间件. 它支持多种类型的数据结构,如 ...

  3. Redis源码-Set:Redis Set存储原理、Redis Set集合操作命令、Redis Set两种存储底层编码intset+hashtable、Redis Set应用场景

    Redis源码-Set:Redis Set存储原理.Redis Set集合操作命令.Redis Set两种存储底层编码intset+hashtable.Redis Set应用场景 Redis数据类型 ...

  4. 【2020尚硅谷Java大厂面试题第三季 04】Redis 9种数据类型使用场景,分布式锁演变步骤,lua脚本,redis事务,Redisson,Redis内存占用,删除策略,内存淘汰策略,手写LRU

    1.安装redis6.0.8 2023 02 02 为:redis-7.0.8.tar.gz 2.redis传统五大数据类型的落地应用 3.知道分布式锁吗?有哪些实现方案?你谈谈对redis分布式锁的 ...

  5. redis相关知识点讲解,redis面试题

    redis相关知识点讲解,redis面试题 1. redis基本知识点 1.1 什么是redis? 1.2 redis的key的设计 1.3 redis的value数据类型有哪些? 1.3.1 str ...

  6. redis php 持久化,详解Redis RDB持久化、AOF持久化,

    详解Redis RDB持久化.AOF持久化, 1.持久化 1.1 持久化简介 持久化(Persistence),持久化是将程序数据在持久状态和瞬时状态间转换的机制,即把数据(如内存中的对象)保存到可永 ...

  7. Redis 之(二) Redis的基本数据结构以及一些常用的操作

    本篇内容是Redis最简单最容易掌握的知识,如果你已经熟知了,就可以选择跳过啦! 要体验Redis,那么首先你得安装Redis,这边的话我就只讲一下Windows环境下的安装与操作: Window 下 ...

  8. php 利用redis写一个聊天室,Redis实现多人多聊天室功能

    本文为大家分享了Redis支持多人多聊天室功能的设计代码,供大家参考,具体内容如下 设计原理 左边的一个数据域,代表两个聊天室,聊天室id分别是827,729 在聊天室827里,有2个人,分别是jas ...

  9. Redis单机系列文章--1.Redis单机的安装和配置(含视频)

    转载请注明出处哈:http://carlosfu.iteye.com/blog/2240426   一.Redis单机下载.编译.安装: cd /opt/soft wget http://downlo ...

最新文章

  1. Spring MVC配置文件的三个常用配置详解
  2. Open×××整合OpenLDAP
  3. mysql 错误记录
  4. 从传递函数到差分方程的转换
  5. 【网络安全】什么是应急响应,应急响应中你到底该关注哪些指标?
  6. 的引用_懵!啥是Java软引用、弱引用、虚引用?
  7. python读取一行的函数_Python linecache.getline()读取文件中特定一行的脚本
  8. RabbitVCS无法启动,右键失效解决方案
  9. 最大似然估计 高斯分布 正态分布
  10. 爱看小说程序源码+4W条数据全站打包
  11. MBA-day4数学-十字交叉法
  12. New File(.)
  13. 吴裕雄--天生自然 诗经:声声慢·寻寻觅觅
  14. Java笔试面试-设计模式
  15. java 吸血鬼数字_java编程思想之吸血鬼数字
  16. js实现自动阅读及停止功能。
  17. Android指定物理按键唤醒屏幕
  18. php 炸金花牌型 和 比牌 规则
  19. 一语中的丨高对抗重实战攻防视角下,企业安全运营到底该怎么做?
  20. yum下载软件包报错 you could try using --skip-broken to work aroundthe problem you should tyr running: rpm

热门文章

  1. Dese:将 JSON API 中图片作为 Windows wallpaper
  2. IE8兼容的js方法
  3. Ubuntu 16.04 Nvidia驱动安装
  4. 教你破解电脑五种开机密码方法
  5. 江协科技课程代码汇集1
  6. 钢琴软件c语言源代码,源代码.c · lijialong1313/C语言钢琴 - Gitee.com
  7. php工程师需要掌握的知识体系
  8. 健身俱乐部综合管理系统/健身房管理系统
  9. 计算机中rm代表什么意思,健身中常见的RM是什么,你了解这个概念吗?了解它很重要...
  10. qt编写的windwos下进程守护程序