阿里云代理商-阿里云服务器-阿里云数据库-重庆典名科技

实现亿级流量下的分布式限流

发布时间: 2020-07-29 09:36:13文章作者: 网站编辑阅读量: 368

       实现亿级流量下的分布式限流    在互联网应用中,系统会面临一个重大的挑战,那就是大量流高并发访问,比如:天猫的双十一、京东618、秒杀、抢购促销等,这些都是典型的大流量场景。系统架构解密,不是所有的秒杀都是秒杀!》

系统限流
    系统限流
    短时间内巨大的访问流量,我们如何让系统在处理高并发的同时还能保证自身系统的稳定性?有人会说,增加机器就可以了,因为我的系统是分布式的,所以可以只需要增加机器就可以解决问题了。但是,如果你通过增加机器还是不能解决这个问题怎么办呢?而且这种情况下又不能无限制的增加机器,服务器的硬件资源始终都是有限的,在有限的资源下,我们要应对这种大流量高并发的访问,就不得不采取一些其他的措施来保护我们的后端服务系统了,比如:缓存、异步、降级、限流、静态化等。
    这里,我们先说说如何实现限流。
    什么是限流?
    在系统中,限流通常指的是:对访问或者请求进行限速或者对一个时间内的请求进行限速来保护我们的系统,一旦达到系统的限速规则(比如系统限制的请求速度),则可以采用下面的方式来处理这些请求。
    拒绝服务(友好提示或者跳转到错误页面)。
    排队或等待(比如秒杀系统)。
    服务降级(返回默认的兜底数据)。
    其实,就是对请求进行限速,比如10r/s,即每秒只允许10个请求,这样就限制了请求的速度。从某种意义上说,限流,其实就是在一定频率上进行量的限制。
    限流一般用来控制系统服务请求的速率,比如:天猫双十一的限流,京东618的限流,12306的抢票等。

分布式限流需要解决什么问题呢

    分布式限流需要解决什么问题呢?我想至少有下面几个:
    1.动态规则:比如限流的QPS我们希望可以动态修改,限流的功能可以随时开启、关闭,限流的规则可以跟随业务进行动态变更等。
    2.集群限流:比如对SpringCloud微服务架构中的某服务下的所有实例进行统一限流,以控制后续访问数据库的流量。
    3.熔断降级:比如在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。
    可选的其它几个功能,诸如实时监控数据、网关流控、热点参数限流、系统自适应限流、黑白名单控制、注解支持等,这些功能其实可以非常方便的进行扩展。

限流有哪些使用场景
    限流有哪些使用场景?
    这里,我们来举一个例子,假设你做了一个商城系统,某个节假日的时候,突然发现提交订单的接口请求比平时请求量突然上涨了将近50倍,没多久提交订单的接口就超时并且抛出了异常,几乎不可用了。而且,因为订单接口超时不可用,还导致了系统其它服务出现故障。
    我们该如何应对这种大流量场景呢?一种典型的处理方案就是限流。当然了,除了限流之外,还有其他的处理方案,我们这篇文章就主要讲限流。
    对稀缺资源的秒杀、抢购;
    对数据库的高并发读写操作,比如提交订单,瞬间往数据库插入大量的数据;
    限流可以说是处理高并发问题的利器,有了限流就可以不用担心瞬间高峰流量压垮系统服务或者服务雪崩,最终做到有损服务而不是不服务。
    使用限流同样需要注意的是:限流要评估好,测试好,否则会导致正常的访问被限流。

    分布式缓存
    缓存更新模式
    CacheAside,常用模式,应用要维护缓存的失效,命中,更新等动作
    Read/WriteThrough,缓存代理更新数据库操作,应用视角只有一份存储
    WriteBehindCache,IO加速方式之一,更新操作只在内测完成,异步进行批量更新数据库

    其实不管处理何种场景,本质都是降低流量保证应用的高可用。
    常见算法
    对于限流常见有两种算法:
    漏桶算法
    令牌桶算法
    漏桶算法比较简单,就是将流量放入桶中,漏桶同时也按照一定的速率流出,如果流量过快的话就会溢出(漏桶并不会提高流出速率)。溢出的流量则直接丢弃。
    如下图所示:

分布式限流,你想知道的都在这里

    这种做法简单粗暴。
    漏桶算法虽说简单,但却不能应对实际场景,比如突然暴增的流量。
    这时就需要用到令牌桶算法:
    令牌桶会以一个恒定的速率向固定容量大小桶中放入令牌,当有流量来时则取走一个或多个令牌。当桶中没有令牌则将当前请求丢弃或阻塞。

    相比之下令牌桶可以应对一定的突发流量。
    RateLimiter实现
    对于令牌桶的代码实现,可以直接使用Guava包中的RateLimiter。

  1. @Override 
  2. public BaseResponse<UserResVO> getUserByFeignBatch(@RequestBody UserReqVO userReqVO) { 
  3.  //调用远程服务 
  4.  OrderNoReqVO vo = new OrderNoReqVO() ; 
  5.  vo.setReqNo(userReqVO.getReqNo()); 
  6.  RateLimiter limiter = RateLimiter.create(2.0) ; 
  7.  //批量调用 
  8.  for (int i = 0 ;i< 10 ; i++){ 
  9.  double acquire = limiter.acquire(); 
  10.  logger.debug("获取令牌成功!,消耗=" + acquire); 
  11.  BaseResponse<OrderNoResVO> orderNo = orderServiceClient.getOrderNo(vo); 
  12.  logger.debug("远程返回:"+JSON.toJSONString(orderNo)); 
  13.  } 
  14.  UserRes userRes = new UserRes() ; 
  15.  userRes.setUserId(123); 
  16.  userRes.setUserName("张三"); 
  17.  userRes.setReqNo(userReqVO.getReqNo()); 
  18.  userRes.setCode(StatusEnum.SUCCESS.getCode()); 
  19.  userRes.setMessage("成功"); 
  20.  return userRes ; 
联系客服免费领取更多阿里云产品新购、续费升级折扣,叠加官网活动折上折更优惠