Rate Limiting

Ограничение скорости (Rate Limiting)|Rate Limiting #

// <em>[Ограничение скорости](http://en.wikipedia.org/wiki/Rate_limiting)</em>
// является важным механизмом контроля использования ресурсов и
// поддержания качества обслуживания. Go элегантно поддерживает
// ограничение скорости с помощью горутин, каналов и [тикеров](tickers).

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())
	}

	// Мы можем разрешить короткие всплески запросов в
	// нашей схеме ограничения скорости при сохранении
	// общего ограничения скорости. Мы можем сделать это
	// путем буферизации нашего канала ограничения. Этот
	// канал `burstyLimiter` будет позволять делать до
	// 3 событий.
	burstyLimiter := make(chan time.Time, 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