秒殺項目之——經過令牌發放機制,控制秒殺大閘以及隊列泄洪

秒殺項目用於處理高併發狀況,咱們採起發放令牌機制,根據用戶的token、商品id、活動商品id和一串uuid產生一個令牌存入redis中redis

同時引入了秒殺大閘,目的是流量控制,好比當前活動商品只有100件,咱們就發放500個令牌,秒殺前會先發放令牌,令牌發放完則把後來的用戶擋在這一層以外,控制了流量算法

獲取令牌後會對比redis中用戶產生的令牌,對比成功才能夠購買商品服務器

 

首先,獲取活動商品詳情時就要根據庫存設置大閘數量,咱們設置大閘爲庫存的5倍

 

 

在發放令牌時就要根據大閘數量判斷要不要發放

 

 

 

這樣一來就減輕了巨大訪問流量帶來的壓力併發

 

可是儘管如此,咱們能夠試想,若是一個網站作秒殺活動,有10個商品秒殺,每一個有1000件,那麼就要發放50000個令牌,這樣的數量仍然很大,因此咱們採起了隊列泄洪來解決此問題app

 

什麼是隊列化泄洪呢,就比如不少人同時進一個門,門很小,人不少,就能夠排成隊,假如一次能進20我的,就20我的一波,一波一波的進負載均衡

同理,隊列化泄洪就是把訪問的用戶分紅批次,來減輕同時巨大的訪問量形成的壓力,通常分爲令牌桶算法和漏桶算法,咱們通常用令牌桶算法,那麼怎麼實現呢?ide

隊列化泄洪——ExecutorService, 經過這個能夠從隊列中每次獲取必定數據量的請求進行處理,處理的速度取決於下游的窗口的處理速度。高併發

 

@Autowired性能

private ExecutorService executorService;網站

@PostConstruct

    public void init(){

        executorService = Executors.newFixedThreadPool(20);

 

}

   //封裝下單請求

    @RequestMapping(value = "/createorder",method = {RequestMethod.POST},consumes={CONTENT_TYPE_FORMED})

    @ResponseBody

    public CommonReturnType createOrder(@RequestParam(name="itemId")Integer itemId,

                                        @RequestParam(name="amount")Integer amount,

                                        @RequestParam(name="promoId",required = false)Integer promoId,

                                        @RequestParam(name="promoToken",required = false)String promoToken) throws BusinessException {

     -------------省略驗證登陸、令牌等信息

        //同步調用線程池的submit方法

        //擁塞窗口爲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(),itemId,promoId,amount,stockLogId)){

                    throw new BusinessException(EmBusinessError.UNKNOWN_ERROR,"下單失敗");

                }

                return null;

            }

        });

 

        try {

            future.get();

        } catch (InterruptedException e) {

            throw new BusinessException(EmBusinessError.UNKNOWN_ERROR);

        } catch (ExecutionException e) {

            throw new BusinessException(EmBusinessError.UNKNOWN_ERROR);

        }

        return CommonReturnType.create(null);

    }

 

 

爲了防止服務器承受不肯定的洪峯流量,能夠採起限流的策略--  單機限流,負載均衡還不錯的狀況下,效果仍是不錯的,每次訪問一個接口,先判斷當前的訪問量是否達到設定值,若是達到了直接回絕。-- Guava Limiter,   設定的訪問值根據咱們壓測的結果設定的--300qps    

集羣限流:依賴redis或者其餘的中間件技術作統一的計數器,每每會產生性能瓶頸

單機限流:負載均衡的前提下,單機限流的效果要好

 咱們使用guava limiter 也就是單機限流,限制單個接口的流量

 

private RateLimiter orderCreateRateLimiter;

 

    @PostConstruct

    public void init(){

        executorService = Executors.newFixedThreadPool(20);

 

        orderCreateRateLimiter = RateLimiter.create(300);

 

}

 

 

在下單以前校驗

if(!orderCreateRateLimiter.tryAcquire()){

            throw new BusinessException(EmBusinessError.RATELIMIT);

 }

相關文章
相關標籤/搜索