年会抢红包技术实现

由于项目需求,研究年会抽红包功能的实现方法,具体实现方法如下:

实现功能:1、PC端大屏幕点击开始抽奖,移动客户端摇一摇,抽红包;
                  2、分多轮抽奖,每一轮抽奖数量事先设定
                  3、奖品丰富不一样
实现逻辑:1、将抽奖批次与数量放入redis缓存当中,并创建奖品信息队列;
                  2、当客户端开始摇一摇时,从redis缓存中获取抽奖批次,判断数量是否大于0,并加锁,获取奖品信息,循环15次,每次先休眠300毫秒;
经压测,可承受10万次的并发
具体实现伪代码如下:

1、将抽奖批次放入内存中:
       JedisPoolConfig config = new JedisPoolConfig(); 
       config.setMaxActive(-1); // 控制一个pool可分配多少个jedis实例
       config.setMaxIdle(3000); // 控制一个pool最多有多少个状态为idle(空闲的)的jedis实例
       config.setTestOnBorrow(true); // 在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的
       config.setMaxWait(30000); // 表示当borrow(引入)一个jedis实例时,最大的等待时间,如果超过等待时间,则直接抛出 JedisConnectionException
       JedisPool jedisPool = new JedisPool(config, IP地址,端口号);
       Jedis jedis = jedisPool.getResource();
        //先删除旧的批次
       String oldMgpbId = jedis.get("批次标识");
        if(StringUtils.isNotBlank(oldMgpbId)){
            jedis.del(oldMgpbId );  
        }
        jedis.del("批次标识");
        jedis.del("奖品队列标识");
        //将抽奖批次与数量放入内存中
        jedis.set("批次标识", "本轮奖品数量");
        //返还到连接池
        jedisPool.returnResource(jedis);
        //奖品信息集合
        List<String> prizes = new ArrayList<String>();
        /**********创建奖品队列***********/
        jedis = jedisPool.getResource();
        //将奖品信息打乱放入队列中
        int prizeNum = 本轮奖品数量;
        for (int j = prizeNum; j > 0; j--) {
            Random random = new Random();
            int num = random.nextInt(j);
            //将奖品信息放入队列中,并从list中移除
            String prize = prizes.remove(num);
            jedis.lpush("奖品队列标识", prize);
        }
        //返还到连接池
        jedisPool.returnResource(jedis);
2、当PC端的大屏幕点击开始抽奖的时候,设置本批次抽奖时间:
        //将抽奖批次的主键放入内存中
        jedis.set("批次标识", "本批次主键");
        //设置失效时间
        jedis.expire("批次标识", 失效时间);
3、移动客户端开始摇奖:
        int m = 0;
        while(m < 15){ //循环15次
            try {
                //休眠300毫秒
                Thread.currentThread().sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //获取抽奖批次主键
            String mgpbId = jedis.get("批次标识");
            if(StringUtils.isBlank(mgpbId)){ //若为空,说明抽奖批次不存在或结束
                logger.info("本轮抽奖已结束");
                break;
            }
          
            if(jedis.setnx("随意参数", "随意参数") == 1){ //加锁成功
                //设置失效时间
                jedis.expire("随意参数", 2); 
                //获取本批次抽奖数量
                int num = Integer.parseInt(jedis.get(mgpbId));
                if(num > 0){ //若数量大于0,则表示中奖了
                    //抽奖数量-1
                    jedis.set(mgpbId, (num -1) + "");
                    //释放锁
                    jedis.del("随意参数");
                    /**************新增中奖信息************/
                    //从奖品信息队列中获取奖品信息
                    List<String> prizeList = jedis.brpop(0, "奖品队列标识");
                    if(CollectionUtils.isEmpty(prizeList)){
                        break;
                    }
                    //取第二个元素
                    String prizeInfo = prizeList.get(1);
                    //解析 prizeInfo 奖品信息,返回信息提示用户中奖
                    break;
                } else if(num == 0){ //若为0,则清空本批次抽奖
                    jedis.del("批次标识"); 
                    jedis.del("本批次主键");
                    //释放锁
                    jedis.del("随意参数");
                    break;
                } 
            } 
            m++;
        }
        jedisPool.returnResource(jedis);


其实主要是利用redis的锁机制以及队列,关于redis,有兴趣的同学可以动手自己搭一个试试。

猜你喜欢

转载自blog.csdn.net/u014526891/article/details/79455593