Rate Limiting
#
// <em>[レート制限](http://en.wikipedia.org/wiki/Rate_limiting)</em>はリソース使用量を管理し、QoS を保つために重要だ。
// Go はゴルーチン、チャネル、[tickers](tickers.html) を使ってうまくレート制限をサポートする。
package main
import (
"fmt"
"time"
)
func main() {
// まずはレートを制限する基本的なやり方を紹介する。
// リクエストを受け取る量を制限したいとする。
// このリクエストをチャネルに流し込む。
requests := make(chan int, 5)
for i := 1; i <= 5; i++ {
requests <- i
}
close(requests)
// チャネル `limiter` は200ミリ秒ごとに値を受信する。
// このチャネルがレート制限のための制御役になる。
limiter := time.Tick(200 * time.Millisecond)
// `limiter` チャネルからの受信がブロックするのを利用して、200ミリ秒ごとにリクエストを受信する。
for req := range requests {
<-limiter
fmt.Println("request", req, time.Now())
}
// リクエストの短期的なバーストを許容しながらも、長期的にはレート制限を守らせることもできる。
// `limiter` にバッファを付ければいいのである。
// チャネル `burstyLimiter` は3つまでのリクエストのバーストを許容する。
burstyLimiter := make(chan time.Time, 3)
// バーストを表す3つの要素をチャネルに送る。
for i := 0; i < 3; i++ {
burstyLimiter <- time.Now()
}
// 200ミリ秒ごとに、`burstyLimiter` に値を送信する。ただし、要素数はチャネルの要素数は最大3である。
go func() {
for t := range time.Tick(200 * time.Millisecond) {
burstyLimiter <- t
}
}()
// ここで、5個リクエストが届いたとする。
// そのうちはじめの3つは `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())
}
}
# プログラムを実行すると、はじめに送ったリクエストの一団は期待した通り200ミリ秒ごとに処理されたことがわかる。
$ 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ミリ秒ごとに処理される。
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