Go速率限制範例


速率限制是控制資源利用和維持服務品質的重要機制。通過goroutineschannelticker都可以優雅地支援速率限制。

首先我們來看一下基本速率限制。假設想限制對傳入請求的處理。我們會在相同名稱的通道上放送這些要求。

這個限制器通道將每200毫秒接收一個值。這是速率限制方案中的調節器。

通過在服務每個請求之前阻塞來自限制器通道的接收,我們限制自己每200毫秒接收1個請求。

我們可能希望在速率限制方案中允許短脈衝串請求,同時保持總體速率限制。可以通過緩衝的限制器通道來實現。這個burstyLimiter通道將允許最多3個事件的突發。

填充通道以表示允許突發。

200毫秒,將嘗試向burstyLimiter新增一個新值,最大限制為3。現在模擬5個更多的傳入請求。這些傳入請求中的前3個未超過burstyLimiter值。

執行程式後,就會看到第一批請求每?200毫秒處理一次。

對於第二批請求,程式會立即服務前3個,因為突發速率限制,然後剩餘2服務都具有?200ms延遲。

所有的範例程式碼,都放在 F:\worksp\golang 目錄下。安裝Go程式設計環境請參考:/2/23/798.html

rate-limiting.go的完整程式碼如下所示 -

package main

import "time"
import "fmt"

func main() {

    // First we'll look at basic rate limiting. Suppose
    // we want to limit our handling of incoming requests.
    // We'll serve these requests off a channel of the
    // same name.
    requests := make(chan int, 5)
    for i := 1; i <= 5; i++ {
        requests <- i
    }
    close(requests)

    // This `limiter` channel will receive a value
    // every 200 milliseconds. This is the regulator in
    // our rate limiting scheme.
    limiter := time.Tick(time.Millisecond * 200)

    // By blocking on a receive from the `limiter` channel
    // before serving each request, we limit ourselves to
    // 1 request every 200 milliseconds.
    for req := range requests {
        <-limiter
        fmt.Println("request", req, time.Now())
    }

    // We may want to allow short bursts of requests in
    // our rate limiting scheme while preserving the
    // overall rate limit. We can accomplish this by
    // buffering our limiter channel. This `burstyLimiter`
    // channel will allow bursts of up to 3 events.
    burstyLimiter := make(chan time.Time, 3)

    // Fill up the channel to represent allowed bursting.
    for i := 0; i < 3; i++ {
        burstyLimiter <- time.Now()
    }

    // Every 200 milliseconds we'll try to add a new
    // value to `burstyLimiter`, up to its limit of 3.
    go func() {
        for t := range time.Tick(time.Millisecond * 200) {
            burstyLimiter <- t
        }
    }()

    // Now simulate 5 more incoming requests. The first
    // 3 of these will benefit from the burst capability
    // of `burstyLimiter`.
    burstyRequests := make(chan int, 5)
    for i := 1; i <= 5; i++ {
        burstyRequests <- i
    }
    close(burstyRequests)
    for req := range burstyRequests {
        <-burstyLimiter
        fmt.Println("request", req, time.Now())
    }
}

執行上面程式碼,將得到以下輸出結果 -

F:\worksp\golang>go run rate-limiting.go
request 1 2017-01-21 14:43:39.1445218 +0800 CST
request 2 2017-01-21 14:43:39.345767 +0800 CST
request 3 2017-01-21 14:43:39.5460635 +0800 CST
request 4 2017-01-21 14:43:39.7441739 +0800 CST
request 5 2017-01-21 14:43:39.9444929 +0800 CST
request 1 2017-01-21 14:43:39.9464898 +0800 CST
request 2 2017-01-21 14:43:39.9504928 +0800 CST
request 3 2017-01-21 14:43:39.9544955 +0800 CST
request 4 2017-01-21 14:43:40.1467214 +0800 CST
request 5 2017-01-21 14:43:40.3469624 +0800 CST