2016-01-07 47 views
1

我一直在試圖爲我的應用程序做一個速率限制器,並且遇到了這個代碼。閱讀完它後,我仍然無法理解它究竟發生了什麼。麻煩了解這個速率限制器如何工作

我目前的理解:

1)SetSmallRateLimit和SetLongRateLimit被調用初始化通道和開始運行的夠程的處理器。

2)當調用requestAndUnmarshal時,checkRateLimiter發送一個信號給隊列通道。

我不明白:

1)RateLimitHandler睡time.After(pertime)的持續時間,之後清除隊列通道。不確定triggerWatcher和returnChan在做什麼。

2)checkTimeTrigger - 不明白這個函數正在做什麼或它的目的。

var (
    smallRateChan rateChan 
    longRateChan rateChan 
) 

type rateChan struct { 
    RateQueue chan bool 
    TriggerChan chan bool 
} 

//10 requests every 10 seconds 
func SetSmallRateLimit(numrequests int, pertime time.Duration) { 
    smallRateChan = rateChan{ 
     RateQueue: make(chan bool, numrequests), 
     TriggerChan: make(chan bool), 
    } 
    go rateLimitHandler(smallRateChan, pertime) 
} 

//500 requests every 10 minutes 
func SetLongRateLimit(numrequests int, pertime time.Duration) { 
    longRateChan = rateChan{ 
     RateQueue: make(chan bool, numrequests), 
     TriggerChan: make(chan bool), 
    } 
    go rateLimitHandler(longRateChan, pertime) 
} 

func rateLimitHandler(RateChan rateChan, pertime time.Duration) { 
    returnChan := make(chan bool) 
    go timeTriggerWatcher(RateChan.TriggerChan, returnChan) 
    for { 
     <-returnChan 
     <-time.After(pertime) 
     go timeTriggerWatcher(RateChan.TriggerChan, returnChan) 
     length := len(RateChan.RateQueue) 
     for i := 0; i < length; i++ { 
      <-RateChan.RateQueue 
     } 
    } 
} 

func timeTriggerWatcher(timeTrigger chan bool, returnChan chan bool) { 
    timeTrigger <- true 
    returnChan <- true 
} 

func requestAndUnmarshal(requestURL string, v interface{}) (err error) { 
    checkRateLimiter(smallRateChan) 
    checkRateLimiter(longRateChan) 
    resp, err := http.Get(requestURL) 
    defer resp.Body.Close() 
    if err != nil { 
     return 
    } 
    checkTimeTrigger(smallRateChan) 
    checkTimeTrigger(longRateChan) 
    if resp.StatusCode != http.StatusOK { 
     return RiotError{StatusCode: resp.StatusCode} 
    } 

    body, err := ioutil.ReadAll(resp.Body) 
    if err != nil { 
     return 
    } 

    err = json.Unmarshal(body, v) 
    if err != nil { 
     return 
    } 
    return 
} 

func checkRateLimiter(RateChan rateChan) { 
    if RateChan.RateQueue != nil && RateChan.TriggerChan != nil { 
     RateChan.RateQueue <- true 
    } 
} 

func checkTimeTrigger(RateChan rateChan) { 
    if RateChan.RateQueue != nil && RateChan.TriggerChan != nil { 
     select { 
     case <-RateChan.TriggerChan: 
     default: 
     } 
    } 
} 

回答

1

我不認爲你應該使用這段代碼來學習任何有用的東西。 我不確定但它似乎試圖限制請求率,但它是錯誤的。它允許進行一定數量的請求,然後等待一段時間。時間間隔後,它允許您再次發出請求。所有這些都是以非常複雜的方式完成的。

但它會導致很奇怪的情況。假設你做1req/h,你的限制是500req/20sec。然後,這段代碼會導致您在500小時後等待20秒,並允許再次發出請求。

checkTimeTrigger從RateChan.TriggerChan中刪除一條消息,如果它有任何消息,並且沒有任何消息,並且它沒有立即返回。

此代碼顯然不是DRY。更好的使用https://godoc.org/golang.org/x/time/rate是你想限制你的請求率。

+0

具有「突發」速率和「長期穩態」速率通常很有用。不一定與您提供的比率(90 000個請求/秒作爲突發速率,0.00028個請求/秒用於穩定狀態)。如果你的值更合理(穩態1請求/秒,突發速率5請求/秒;比方說),這是一個有用的速率限制方法。 – Vatine