レートリミット (Rate limiting) は、リソースの使用量を制御し、サービスの品質を維持するための、 とても重要な仕組みです。 Go は、ゴルーチンとチャネル、ティッカー により、 レートリミットをエレガントにサポートします。 |
|
package main |
|
import ( "fmt" "time" ) |
|
func main() { |
|
まず最初に、基本的なレートリミットを見ていきます。
リクエストに対する処理を制限したいとしましょう。
これらのリクエストに同じ名前の |
requests := make(chan int, 5) for i := 1; i <= 5; i++ { requests <- i } close(requests) |
|
limiter := time.Tick(200 * time.Millisecond) |
各リクエストを処理する前に |
for req := range requests { <-limiter fmt.Println("request", req, time.Now()) } |
あるいは、全体としてはレートリミットを担保しつつ、
一時的なバーストリクエストは許容したいと思うかもしれません。
その場合、 |
burstyLimiter := make(chan time.Time, 3) |
許容されているバースト量を表すため、 チャネルに値を満たしておきます。 |
for i := 0; i < 3; i++ { burstyLimiter <- time.Now() } |
200 ミリ秒ごとに、 |
go func() { for t := range time.Tick(200 * time.Millisecond) { burstyLimiter <- t } }() |
それでは、5 リクエストきた場合をシミュレートします。
これらのうち最初の 3 リクエストは、 |
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()) } } |
プログラムを実行すると、リクエストの前半部分は、期待通り 200 ミリ秒に 1 回処理されていることが分かります。 |
$ go run rate-limiting.go request 1 2012-10-19 00:38:18.687438 +0000 UTC request 2 2012-10-19 00:38:18.887471 +0000 UTC request 3 2012-10-19 00:38:19.087238 +0000 UTC request 4 2012-10-19 00:38:19.287338 +0000 UTC request 5 2012-10-19 00:38:19.487331 +0000 UTC |
リクエストの後半部分は、最初の 3 つはすぐに処理され、 残り 2 つはその後 200 ミリ秒ずつ遅れて実行されていることが 分かります。3 つまではバーストを許容しているからです。 |
request 1 2012-10-19 00:38:20.487578 +0000 UTC request 2 2012-10-19 00:38:20.487645 +0000 UTC request 3 2012-10-19 00:38:20.487676 +0000 UTC request 4 2012-10-19 00:38:20.687483 +0000 UTC request 5 2012-10-19 00:38:20.887542 +0000 UTC |
Next example: Atomic Counters.