秒杀项目之——经过令牌发放机制,控制秒杀大闸以及队列泄洪

秒杀项目用于处理高并发状况,咱们采起发放令牌机制,根据用户的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);

 }

相关文章
相关标签/搜索