RateLimiter的 SmoothBursty(非warmup預熱)及SmoothWarmingUp(預熱,冷啟動)


SmoothBursty

主要思想

記錄 1秒內的微秒數/permitsPerSencond = 時間間隔interval,每一個interval可獲得一個令牌
根據允許使用多少秒內的令牌參數,計算出maxPermits
setRate時初始化下次interval時間,及storedPermits

acquire時,計算當前nowMicros,如果大於下次interval時間時間,則更新storedPermits和下次interval時間,計算storedPermits能否滿足此次acquire,如果能,則需要等待的時間為0,如果不能,則計算還需要多少微秒等待,並在非同步塊外執行sleep操作

如果其他線程已經刷新了nextFreeTicketMicros,會如下情況acquire是無timeout的

Thread 1: acquire 11 -> storedPermits不能滿足要求 -> waitTime = (acquire - stored) * stableIntervalMicros -> nextFreeTicketMicros += waitMicros ----->  out lock sleep
Thread 2: acquire 2 -> nowMicros < nextFreeTicketMicros , stored = 0,被線程1消耗完了 -> freshPermits = requiredPermits - storedPermitsToSpend 即 = requiredPermits -> waitTime = freshPermits * stableIntervalMicros
-> nextFreeTicketMicros += waitTime,此時的nextFreeTicketMicros包含了Thread1需要等待的時間 -------> out lock sleep a longer time

tryAquire(num,timeout)邏輯

timeoutMicros = timeout.toMicros
lock()
nowMicros = ...
canAcquire = nextFreeTicketMicros <= nowMicros + timeoutMicros
if(!canAcquire){
 return false;
}
else{
  microsToWait = ...
} 
unlock()
sleep(microsToWait)
return true;

SmoothWarmingUp

主要思想和SmoothBursty相似,由於帶預熱過程,剛開始由於availablePermitsAboveThreshold>0.0,速率會較慢,如果持續獲取令牌,則會使availablePermitsAboveThreshold=0,速率變快

  • 從0->thresholdPermits,生成一個令牌的時間:stableIntervalMicros

  • 從thresholdPermits-> maxPermits ,生成一個令牌的時間:stableIntervalMicros + permits * slope;

    @Override
    final long reserveEarliestAvailable(int requiredPermits, long nowMicros) {
    resync(nowMicros);
    long returnValue = nextFreeTicketMicros;
    //當前需要且盡最大可能消費的
    double storedPermitsToSpend = min(requiredPermits, this.storedPermits);
    //新鮮permits個數,這些個數是一定會產生等待的,除了0
    double freshPermits = requiredPermits - storedPermitsToSpend;
    //計算需要wait的總時間
    long waitMicros =
    //非busty類型的storedPermitsToWaitTime直接返回0
    storedPermitsToWaitTime(this.storedPermits, storedPermitsToSpend)
    + (long) (freshPermits * stableIntervalMicros);
    //下次有票時間
    this.nextFreeTicketMicros = LongMath.saturatedAdd(nextFreeTicketMicros, waitMicros);
    this.storedPermits -= storedPermitsToSpend;
    return returnValue;
    }

     //已知permitsToTake <= storedPermits
     @Override
     long storedPermitsToWaitTime(double storedPermits, double permitsToTake) {
       //減去預熱需要保留的permits,剩下的可消耗的數量
       double availablePermitsAboveThreshold = storedPermits - thresholdPermits;
       long micros = 0;
       // measuring the integral on the right part of the function (the climbing line)
       //如果有剩余可用的令牌
       if (availablePermitsAboveThreshold > 0.0) {
        //剩余可用的和需要獲取的個數取小值
     	double permitsAboveThresholdToTake = min(availablePermitsAboveThreshold, permitsToTake);
     	// TODO(cpovirk): Figure out a good name for this variable.
     	//用可消耗的數量 + (可消耗的數量 - 實際消耗的數量)permitsToTime
     	//在預熱階段從thresholdPermits到maxPermits的耗時並非是stableIntervalMicros * n
     	//會耗費更多的時間,其計算規則不同,所以才需要把permitsAboveThresholdToTake從permitsToTake減去
     	//length 可能作為一個經驗值,相當於補充permitsAboveThresholdToTake個令牌需要的平均時間值*2
                     //剩余可用的-實際需要且最大能消耗的令牌,得到最終剩余的令牌個數,可能是0
     	double length = permitsToTime(availablePermitsAboveThreshold)
     	    + permitsToTime(availablePermitsAboveThreshold - permitsAboveThresholdToTake);
     	//這里確實不好理解,從語義環境來說,它是從 thresholdPermits 到 maxPertmis 過程中
     	//生成 permitsAboveThresholdToTake 個令牌需要耗費的時間
     	//並且帶coldFactor的構造函數不是public,SmoothWarmingUp也是private-package的
     	micros = (long) (permitsAboveThresholdToTake * length / 2.0);
     	//從permitsToTake中減去保留預熱需留下個數后最終消耗的個數,這部分個數由於是提前存在的、富余的
     	//因此不需要計算到wait時間
     	permitsToTake -= permitsAboveThresholdToTake;
       }
       // measuring the integral on the left part of the function (the horizontal line)
       //如果沒有剩余可用令牌,走的是stableIntervalMicros * n
       micros += (stableIntervalMicros * permitsToTake);
       return micros;
     }	
    

length/2可以理解為下圖

	//permits值越小,需要的時間就越少,值越大,需要的時間就越大
	private double permitsToTime(double permits) {
	  //double coldIntervalMicros = stableIntervalMicros * coldFactor;
	  // thresholdPermits = 0.5 * warmupPeriodMicros / stableIntervalMicros;
      //maxPermits =
      thresholdPermits + 2.0 * warmupPeriodMicros / (stableIntervalMicros + coldIntervalMicros);
      //slope帶比率的時間,可以理解為增長因子
	  //slope =  (coldIntervalMicros - stableIntervalMicros) / (maxPermits - thresholdPermits)
	  //return表示成這樣更易於理解 stableIntervalMicros + (coldIntervalMicros - stableIntervalMicros) * (permits/(maxPermits - thresholdPermits))
	  return stableIntervalMicros + permits * slope;
	}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM