zoukankan      html  css  js  c++  java
  • 秒杀项目之——通过令牌发放机制,控制秒杀大闸以及队列泄洪

    秒杀项目用于处理高并发情况,我们采取发放令牌机制,根据用户的token、商品id、活动商品id和一串uuid产生一个令牌存入redis中

    同时引入了秒杀大闸,目的是流量控制,比如当前活动商品只有100件,我们就发放500个令牌,秒杀前会先发放令牌,令牌发放完则把后来的用户挡在这一层之外,控制了流量

    获取令牌后会对比redis中用户产生的令牌,对比成功才可以购买商品

    首先,获取活动商品详情时就要根据库存设置大闸数量,我们设置大闸为库存的5倍

    在发放令牌时就要根据大闸数量判断要不要发放

    这样一来就减轻了巨大访问流量带来的压力

    但是尽管如此,我们可以试想,如果一个网站做秒杀活动,有10个商品秒杀,每个有1000件,那么就要发放50000个令牌,这样的数量仍然很大,所以我们采取了队列泄洪来解决此问题

    什么是队列化泄洪呢,就好比很多人同时进一个门,门很小,人很多,就可以排成队,假如一次能进20个人,就20个人一波,一波一波的进

    同理,队列化泄洪就是把访问的用户分成批次,来减轻同时巨大的访问量造成的压力,一般分为令牌桶算法和漏桶算法,我们一般用令牌桶算法,那么怎么实现呢?

    队列化泄洪——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);

     }

     

      

  • 相关阅读:
    联合查询
    单表查询
    表和表之间的关系
    mysql完整性约束
    mysql 数据类型
    DRBD 数据镜像软件
    Memcached
    Redis
    SVN版本控制服务
    大数据hadoop分布式系统
  • 原文地址:https://www.cnblogs.com/blogofbin/p/11704158.html
Copyright © 2011-2022 走看看