流量削峯技術

改進的點

  • 之前的秒殺下單接口被腳本不停的刷
  • 秒殺驗證邏輯和秒殺下單接口強關聯,代碼冗餘度高
  • 秒殺驗證邏輯複雜,對交易系統產生無關聯複雜

在這裏插入圖片描述

秒殺令牌

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述


  //申城秒殺令牌
    //校驗用戶以及商品
    @Override
    public String generateSecondKillToken(Integer promoId,Integer itemId,Integer userId) {
        //獲取對應商品的秒殺活動信息
        PromoDO promoDO = promoDOMapper.selectByPrimaryKey(promoId);

        //dataobject->model
        PromoModel promoModel = convertFromDataObject(promoDO);
        if(promoModel == null){
            return null;
        }

        //判斷當前時間是否秒殺活動即將開始或正在進行,若不是無法生成令牌
        if(promoModel.getStartDate().isAfterNow()){
            promoModel.setStatus(1);
        }else if(promoModel.getEndDate().isBeforeNow()){
            promoModel.setStatus(3);
        }else{
            promoModel.setStatus(2);
        }


        //
        //使用緩存校驗itemModel
        ItemModel itemModel = itemService.getItemByIdInCache(itemId);
        if(itemModel == null){
                return null;
        }

        //判斷用戶是否存在
        UserModel userModel = userService.getUserByIdInCache(userId)

        if(userModel == null){
            return null;
        }


        //生成tockey存入redis內,並給一個5分鐘的有效期
        if(promoModel.getStatus().intValue()!=2){
            return null;
        }else{

            //獲取秒殺大閘的count數量
           long result = redisTemplate.opsForValue().increment("promo_door_count_" + promoId,-1);
            if(result<0) return  null;


            //生成一個秒殺令牌
            String token = UUID.randomUUID().toString().replace("-","");
            redisTemplate.opsForValue().set("promo_token_"+promoId+"_userid_"+userId+"_itemid_"+itemId,token);
            redisTemplate.expire("promo_token_"+promoId+"_userid_"+userId+"_itemid_"+itemId,5, TimeUnit.MINUTES);
            return token;
        }
    }

在這裏插入圖片描述

秒殺大閘

在這裏插入圖片描述


//限制秒殺令牌的數量:多少個用戶可以獲取到秒殺令牌
 //將秒殺大閘限制到redis內
        redisTemplate.opsForValue().set("promo_door_count_"+promoId,itemModel.getStock().intValue()*4); 

在這裏插入圖片描述
在這裏插入圖片描述

隊列泄洪(擁塞窗口)

在這裏插入圖片描述

在orderController中有用戶下單時,使用線程池,從線程池中選取線程進行操作,每次最多有20個用戶可以進行下單的操作



        //同步調用線程池的submit方法
        //同步調用線程池的subnmit方法
        //擁塞窗口爲20的等待隊列,用來隊列化泄洪
       Future<Object> future =  executorService.submit(new Callable<Object>() {
            @Override
            public Object call() throws Exception {
                //加入庫存流水init狀態
                String stockLogId = itemService.initStockLog(itemId,amount);

                if(!mqProducer.transactionAsyncReduceStock(userModel.getId(),promoId,itemId,amount,stockLogId)){
                    throw new BusinessException(EmBusinessError.UNKNOWN_ERROR,"下單失敗");
                }

                return null;
            }
        });

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章