【限流】——RateLimiter限流方案

背景

在说限流方案之前我们需要知道在什么样的场景下需要限流,以前我们都是应用部署在单台机器上,但是随着流量的增大单台服务已经扛不住压力了,所以就变成了新的的集群部署,将流量压力分担到多台机器上,来提高吞吐量,但是互联网企业嘛,在一些节日或者特殊的日子里会搞一些抢购的活动,这个并发压力可能是平时的很多倍吧,按照正常的思路来说我们增加机器横向扩展吧,可是平时的话流量没有这么大,购买这些机器其实是非常浪费的,而且我们的抢购只是流量大,但是实际的有效流量是很少的,所以限流方案出来了,guava的工具类中RateLimiter就提供了这样的功能,下面来看下几种限流方案。

一、限流方案

1、计数器方式

采用AtomicInteger:

     使用AomicInteger来进行统计当前正在并发执行的次数,如果超过域值就简单粗暴的直接响应给用户,说明系统繁忙,请稍后再试或其它跟业务相关的信息。

    弊端:使用 AomicInteger 简单粗暴超过域值就拒绝请求,可能只是瞬时的请求量高,也会拒绝请求。

 采用令牌Semaphore:

     使用Semaphore信号量来控制并发执行的次数,如果超过域值信号量,则进入阻塞队列中排队等待获取信号量进行执行。如果阻塞队列中排队的请求过多超出系统处理能力,则可以在拒绝请求。

    相对Atomic优点:如果是瞬时的高并发,可以使请求在阻塞队列中排队,而不是马上拒绝请求,从而达到一个流量削峰的目的。

 采用ThreadPoolExecutor java线程池:

    固定线程池大小,超出固定先线程池和最大的线程数,拒绝线程请求;

2、令牌桶方式

令牌桶算法是网络流量整形(Traffic Shaping)和速率限制(Rate Limiting)中最常使用的一种算法。先有一个木桶,系统按照固定速度,往桶里加入Token,如果桶已经满了就不再添加。当有请求到来时,会各自拿走一个Token,取到Token 才能继续进行请求处理,没有Token 就拒绝服务。

  这里如果一段时间没有请求时,桶内就会积累一些Token,下次一旦有突发流量,只要Token 足够,也能一次处理,所以令牌桶算法的特点是允许突发流量。

    我们看一个例子,看看令牌桶如何允许突发流量,假如令牌则按照每秒5 个的速度放入令牌桶,桶中最多存放20 个令牌,那系统可以支持两种类型的请求流量,一种是允许持续的每秒处理5 个请求,第二种是每隔4 秒,等桶中20 个令牌攒满后,就可以处理一次有20 个请求的突发情况。

令牌桶的方案设计:

  使用guava提供工具库里的RateLimiter类(内部采用令牌捅算法实现)进行限流

3、漏桶算法

    一个固定容量的漏桶,按照常量固定速率流出水滴;

      先想象有一个木桶,新请求就像水滴一样,不断地滴进来,水滴进来的速度是不确定的,有时会快一点,有时会慢一点,同时桶底下有个洞,可以按照固定的速度把水漏走,如果水进来的速度比漏走的快,桶就会满了,桶满了水就会漫出来,对应的就是拒绝请求。

  漏桶算法的主要特点是可以平滑网络上的突发流量,请求可以被整形成稳定的流量。

二、实现(令牌通方式)

1、代码

 public static void main(String[] args) throws InterruptedException {
        RateLimiter limiter = RateLimiter.create(5);
        long start = System.currentTimeMillis();
        System.out.println("start:"+start);
        for (int i = 0; i <20 ; i++) {
            Thread.sleep(10);
            boolean getToken  =limiter.tryAcquire();
            if (getToken){
                System.out.println("获取了令牌====="+(i+1));
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("end:"+end);
        System.out.println("花费时间:"+(end-start)+"毫秒");

        RateLimiter limiter1 = RateLimiter.create(1);
        System.out.println(limiter1.acquire(10));
        System.out.println(limiter1.acquire());
        System.out.println(limiter1.acquire());
        System.out.println(limiter1.acquire());
        System.out.println(limiter1.acquire());
        System.out.println(limiter1.acquire());
        System.out.println(limiter1.acquire());
        System.out.println(limiter1.acquire());
        System.out.println(limiter1.acquire());
    }

2、结果

start:1575013943433
获取了令牌=====1
获取了令牌=====19
end:1575013943652
花费时间:219毫秒
0.0
9.998836
0.99797
1.000141
0.998961
0.99968
0.999161
0.999291
Disconnected from the target VM, address: '127.0.0.1:62636', transport: 'socket'
0.999234

Process finished with exit code 0

参考:http://www.dczou.com/viemall/852.html

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值