常用限流算法:令牌桶和漏桶算法解析

漏桶算法

漏桶算法思路很簡單,水(請求)先進入到漏桶裏,漏桶以一定的速度出水,當水流入速度過大會直接溢出,可以看出漏桶算法能強行限制數據的傳輸速率。
漏桶算法示意圖

令牌桶算法

對於很多應用場景來說,除了要求能夠限制數據的平均傳輸速率外,還要求允許某種程度的突發傳輸。這時候漏桶算法可能就不合適了,令牌桶算法更爲適合。如圖2所示,令牌桶算法的原理是系統會以一個恆定的速度往桶裏放入令牌,而如果請求需要被處理,則需要先從桶裏獲取一個令牌,當桶裏沒有令牌可取時,則拒絕服務。
令牌桶算法示意圖

限流工具類RateLimiter

  Google開源工具包Guava提供了限流工具類RateLimiter,該類基於令牌桶算法來完成限流,非常易於使用。具體使用可以自行百度。下面是RateLimiter的源碼:

public double acquire() {
        return acquire(1);
    }

 public double acquire(int permits) {
        checkPermits(permits);  //檢查參數是否合法(是否大於0)
        long microsToWait;
        synchronized (mutex) { //應對併發情況需要同步
            microsToWait = reserveNextTicket(permits, readSafeMicros()); //獲得需要等待的時間 
        }
        ticker.sleepMicrosUninterruptibly(microsToWait); //等待,當未達到限制時,microsToWait爲0
        return 1.0 * microsToWait / TimeUnit.SECONDS.toMicros(1L);
    }

private long reserveNextTicket(double requiredPermits, long nowMicros) {
        resync(nowMicros); //補充令牌
        long microsToNextFreeTicket = nextFreeTicketMicros - nowMicros;
        double storedPermitsToSpend = Math.min(requiredPermits, this.storedPermits); //獲取這次請求消耗的令牌數目
        double freshPermits = requiredPermits - storedPermitsToSpend;

        long waitMicros = storedPermitsToWaitTime(this.storedPermits, storedPermitsToSpend)
                + (long) (freshPermits * stableIntervalMicros); 

        this.nextFreeTicketMicros = nextFreeTicketMicros + waitMicros;
        this.storedPermits -= storedPermitsToSpend; // 減去消耗的令牌
        return microsToNextFreeTicket;
    }

private void resync(long nowMicros) {
        // if nextFreeTicket is in the past, resync to now
        if (nowMicros > nextFreeTicketMicros) {
            storedPermits = Math.min(maxPermits,
                    storedPermits + (nowMicros - nextFreeTicketMicros) / stableIntervalMicros);
            nextFreeTicketMicros = nowMicros;
        }
    }
發佈了58 篇原創文章 · 獲贊 32 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章