接口限流算法:漏桶算法和令牌桶算法

漏桶算法java

漏桶能够看做是一个带有常量服务时间的单服务器队列,若是漏桶(包缓存)溢出,那么数据包会被丢弃。这一点和线程池原理是很类似的。redis

把请求比做是水,水来了都先放进桶里,并以限定的速度出水,当水来得过猛而出水不够快时就会致使水直接溢出,即拒绝服务。算法

须要注意的是,在某些状况下,漏桶算法不可以有效地使用网络资源,由于漏桶的漏出速率是固定的,因此即便网络中没有发生拥塞,漏桶算法也不能使某一个单独的数据流达到端口速率。所以,漏桶算法对于存在突发特性的流量来讲缺少效率。而令牌桶算法则可以知足这些具备突发特性的流量。api

令牌桶算法缓存

令牌桶算法是网络流量整形(Traffic Shaping)和速率限制(Rate Limiting)中最常使用的一种算法。典型状况下,令牌桶算法用来控制发送到网络上的数据的数目,并容许突发数据的发送。服务器

令牌桶算法的原理是系统会以一个恒定的速度往桶里放入令牌,而若是请求须要被处理,则须要先从桶里获取一个令牌,当桶里没有令牌可取时,则拒绝服务。从原理上看,令牌桶算法和漏桶算法是相反的,一个“进水”,一个是“漏水”。网络

单机限流多线程

Google的Guava包中的RateLimiter类就是令牌桶算法的解决方案。 首先说下单机限流分布式

package yzy.guava.test;

import com.google.common.base.Optional;
import com.google.common.util.concurrent.RateLimiter;

import java.nio.channels.ServerSocketChannel;

public class OptionalTest {
    public void guava()
    {
        //guava
        Optional<Integer> possible = Optional.of(6);
        if(possible.isPresent())
        {
            System.out.println("possible isPresent:" +
                    possible.isPresent());
            System.out.println("possible value:" + possible.get());
            ServerSocketChannel s =null;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        OptionalTest hello = new OptionalTest();
        hello.guava();


        RateLimiter limiter = RateLimiter.create(1);//限制qps最大为1
        System.out.println(limiter.acquire()); //输出阻塞的时间

        Thread.sleep(2000);
        System.out.println(limiter.acquire() + " " + System.currentTimeMillis() / 1000 );

        System.out.println(limiter.acquire() + " " + System.currentTimeMillis() / 1000);

        System.out.println(limiter.acquire() + " " + System.currentTimeMillis() / 1000);



        System.out.println(limiter.acquire() + " " + System.currentTimeMillis() / 1000);
        System.out.println(limiter.acquire() + " " + System.currentTimeMillis() / 1000);

        System.out.println(limiter.acquire() + " " + System.currentTimeMillis() / 1000);

    }
}

分布式限流ui

基于Redis的分布式限流器能够用来在分布式环境下如今请求方的调用频率。既适用于不一样Redisson实例下的多线程限流,也适用于相同Redisson实例下的多线程限流。该算法不保证公平性。

RRateLimiter rateLimiter = redisson.getRateLimiter("myRateLimiter");
// 初始化
// 最大流速 = 每1秒钟产生10个令牌
rateLimiter.trySetRate(RateType.OVERALL, 10, 1, RateIntervalUnit.SECONDS);

// 获取4个令牌
rateLimiter.tryAcquire(4);

// 尝试获取4个令牌,尝试等待时间为2秒钟
rateLimiter.tryAcquire(4, 2, TimeUnit.SECONDS);

rateLimiter.tryAcquireAsync(2, 2, TimeUnit.SECONDS);

// 尝试获取1个令牌,等待时间不限
rateLimiter.acquire();

// 尝试获取1个令牌,等待时间不限
RFuture<Void> future = rateLimiter.acquireAsync();
相关文章
相关标签/搜索