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

漏桶算法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();
相關文章
相關標籤/搜索