分布式三大利器之限流

一、什么是服务限流

什么是服务限流呢?限流即限制并发量,限制某一段时间只有指定数量的请求进入后台服务器,遇到流量高峰期或者流量突增时,把流量速率限制在系统所能接受的合理范围之内,不至于让系统被高流量击垮。限流与缓存、降级统称为分布式系统的三大利器,最终目的都是用来保护系统稳定运行。

二、如何实现服务限流

怎么实现服务限流呢?开发过程中或多或少会接触到服务限流,比如tomcat限制最大连接数、数据库连接池限制连接数、nginx限制ip访问数、秒杀、抢购等。这些都是通过限制一个时间窗口内的请求数,当达到设置的最大请求数后,会让后续请求进入等待队列或直接拒绝,防止系统过载。这些限流是怎么做到的呢,或者说限流主要有哪些方式呢?很多人把限流归纳成4种场景,其实也不外乎这4种场景,它们分别是:

1)限制总并发数或请求数

从系统层面维护一个计数器,每来一个请求就将计数器加1,请求处理完后将计数器减1,当计数器大于设定的阀值时,拒绝请求或将请求放入等待队列。这是最简单粗暴的限流方式,实现起来比较简单,但它有个很明显的缺陷是如果某一时间段系统受到恶意攻击(即突发请求),若并发数大于阀值时,后续有效的请求都会被拒绝,因而这种方法在现实中的使用并不常见

2)限制接口的总并发或请求数

针对每个接口维护一个计数器,每来一个请求就将对应接口的计数器加1,请求处理完后将计数器减1,当计数器大于设定的阀值时,拒绝请求或将请求放入等待队列。这种方式较之第一种稍复杂些,如果要用aop去实现的话,则需要定义多个切面,维护成本也随之加大,它虽然不能应对接口受到恶意攻击(即突发请求),但较之第一种方式有个好处是,即使遭到攻击,也只会造成某个接口不可用,影响面小很多。实现同场景1。

3)限制接口每秒的请求数

     这种方式和第二种很相似,只是它把时间窗口缩小到1秒,故而影响范围更小,实现如下:

// 存放令牌的缓存,失效时间为1s,缓存的key为当前时间秒值,value为这一秒对应的请求数,以当前时间秒值作为key的好处是方 
// 便统计一秒产生的请求总数,且下一秒到来时,数据会被自动清空
LoadingCache<Long, AtomicLong> tokenCache = CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.SECONDS).build(new CacheLoader<Long, AtomicLong>() {
      @Override
      public AtomicLong load(Long seconds) throws Exception {
           return new AtomicLong(0);
      }
});
// 每秒最大请求数
long limit = 200;
while(true) {
    Long currentSeconds = System.currentTimeMillis() / 1000;
    if(tokenCache.get(currentSeconds).incrementAndGet() > limit) {
        log.info("该请求被限流了");
        continue;
    }
    //do-business
}

作者:有赞美业商家经营组技术博客
链接:https://juejin.im/post/5c34892be51d45521315edab
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

4)平滑限流接口的请求数 

平滑限流接口是为了对突发请求进行整形,以平均速率处理请求,故而可以应对突发请求,也是目前用的较多的限流方式。其分为平滑突发限流(SmoothBursty)、平滑预热限流(SmoothWarmingUp)两种模式,限流算法有令牌桶法、漏桶法。Google对Guava工具包提供了令牌桶的算法实现,使用起来也很简单、方便,下面会介绍令牌桶法、漏桶法。

三:限流算法

1)令牌桶法

令牌桶法是以固定速率往桶里添加令牌,当令牌数达到上限时,便会丢弃或拒绝,其流程图如下:

令牌以固定速率放入桶中,如每秒放入r个; 桶中最多存放b个令牌,当桶中令牌数达到上限时,便丢弃或拒绝; 当需从桶中获取n个令牌时,若桶中令牌数大于n,便会删除桶里的n个令牌,否则请求等待。

 

2)漏桶法

漏桶法允许以任意速率流入桶内,但流出速率是恒定的,桶满了则丢弃令牌,桶内没有令牌时则阻塞,其流程图如下:

 

令牌以任意速率流入桶中; 以固定速率流出令牌,如果桶是空的,则不用流出; 若流入的令牌数超出了桶的容量,则令牌被丢弃。 由于令牌桶算法是以恒定速率流入桶中,令牌可以以任意速率流出,因而只需调整令牌流入速率便可解决流量突发情况,同时也支持预先消费,而漏桶算法是令牌以任意速率流入桶中,以恒定速率流出,从而不能解决流量突发情况(如常用的队列),如此对比令牌桶法相对漏桶法更优,但业务上不能一味的追求使用令牌桶法去实现,主要还需根据业务需求来断定使用那个限流算法。

 

四:总结

限流做为保护系统的一种常用方式,以限制系统的输入和输出流量已达到保护系统,业界也提供了很多现有的框架可直接使用,如jdk提供的Semaphore、google提供的Guava、Netflix提供的hystrix等,Semaphore是最简单粗暴的,直接使用计数器来控制。guava则采用了令牌桶法,可以平滑的进行限流。hystrix则提供了多种限流策略,使用起来更灵活,同时使用复杂度相对大一些,后续会介绍Semaphore、Guava、hystrix的实现原理。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值