本文主要研究一下token bucket算法的實現git
主要有以下幾種:github
只有數量維度,沒有時間維度
帶上了時間維度,不過在兩個窗口的臨界點容易出現超出限流的狀況,好比限制每分鐘10個請求,在00:59請求了10次,在01:01又請求了10次,而從00:30-01:30這個時間窗口來看,這一分鐘請求了20次,沒有控制好
就是要解決fixed window沒解決的窗口臨界問題,主要有基於token bucket的算法,以及基於leaky bucket的算法
可能等待token足夠再繼續
)/** * The minimalistic token-bucket implementation */ public class MinimalisticTokenBucket { private final long capacity; private final double refillTokensPerOneMillis; private double availableTokens; private long lastRefillTimestamp; /** * Creates token-bucket with specified capacity and refill rate equals to refillTokens/refillPeriodMillis */ public MinimalisticTokenBucket(long capacity, long refillTokens, long refillPeriodMillis) { this.capacity = capacity; this.refillTokensPerOneMillis = (double) refillTokens / (double) refillPeriodMillis; this.availableTokens = capacity; this.lastRefillTimestamp = System.currentTimeMillis(); } synchronized public boolean tryConsume(int numberTokens) { refill(); if (availableTokens < numberTokens) { return false; } else { availableTokens -= numberTokens; return true; } } private void refill() { long currentTimeMillis = System.currentTimeMillis(); if (currentTimeMillis > lastRefillTimestamp) { long millisSinceLastRefill = currentTimeMillis - lastRefillTimestamp; double refill = millisSinceLastRefill * refillTokensPerOneMillis; this.availableTokens = Math.min(capacity, availableTokens + refill); this.lastRefillTimestamp = currentTimeMillis; } } private static final class Selftest { public static void main(String[] args) { // 100 tokens per 1 second MinimalisticTokenBucket limiter = new MinimalisticTokenBucket(100, 100, 1000); long startMillis = System.currentTimeMillis(); long consumed = 0; while (System.currentTimeMillis() - startMillis < 10000) { if (limiter.tryConsume(1)) { consumed++; } } System.out.println(consumed); } } }
token bucket算法,是基於qps來限流,其簡單的實現,就是計算單位時間補充token的速率,而後每次tryConsume的時候根據速率修正availableTokens。算法