Rate Limiting

Обмеження Частоти Запитів|Rate Limiting #

// [_Обмеження Частоти Запитів_](http://en.wikipedia.org/wiki/Rate_limiting)
// важливий механізм контролю за ресурсами, його використовують
// для підтримки необхідного рівня роботи (і обмеження навантаження
// на сервера з сторонніх джерел). Реалізація обмежувача в Go є можливою
// за допомоги [горутин](goroutines), [каналів](channels) та [маятників](tickers).

package main

import (
	"fmt"
	"time"
)

func main() {

	// Розглянемо одну з реалізацій обмежувача частоти запитів.
	// Припустимо - нам необхідно обмежити обробку
	// вхідних запитів, отож, ми будемо працювати з ними (запитами)
	// через одноіменний канал (`requests`).
	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`
	// дозволятиме напливи, аж, трьох подій.
	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`, який блокує доступ
	// для 4-того та 5-того запитів, аж до моменту коли
	// сам канал "обмежувач" не буде знову наповнено.
	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

# Друга ж партія, представляє собою
# три запити що не обмежуються (це "навала"
# - дозволена кількість без обмеження) та
# ще 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