Rate Limiting

Rate Limiting #

// Il [_Rate limiting_](https://en.wikipedia.org/wiki/Rate_limiting)
// è un'importante tecnica per controllare l'uso delle
// risorse e mantenere un'alta qualità di servizio. Go
// supporta elegantemente il rate limiting tramite le
// goroutine, i channel e i [ticker](ticker).

package main

import "time"
import "fmt"

func main() {

    // Come prima cosa vedremo un semplice esempio di rate
    // limiting. Supponiamo di dover limitare il
    // numero di richieste (per esempio in un server
    // HTTP). Utilizzeremo un channel per
    // mimare l'entrata delle richieste.
    richieste := make(chan int, 5)
    for i := 1; i <= 5; i++ {
        richieste <- i
    }
    close(richieste)

    // Questo channel `limitatore` riceverà un valore ogni
    // 200 millisecondi. Fungerà da regolatore nel
    // nostro schema di rate limiting.
    limitatore := time.Tick(time.Millisecond * 200)

    // Bloccando l'esecuzione su una ricezione da
    // `limitatore` prima di servire ogni richiesta, ci
    // limitiamo a fare al massimo una richiesta ogni
    // 200 millisecondi.
    for ric := range richieste {
        <-limitatore
        fmt.Println("richiesta", ric, time.Now())
    }

    // Potremmo aver bisogno di sostenere brevi
    // "raffiche" di richieste, mantenendo comunque
    // il rate limiting. Possiamo fare ciò mettendo
    // bufferizzando il nostro channel. Questo channel
    // `limitatoreARaffica` ci permetterà di sostenere
    // raffiche fino ad un massimo di 3 richieste.
    limitatoreARaffica := make(chan time.Time, 3)

    // Riempiamo il channel per dire che già dall'inizio
    // possiamo prendere in carico 3 richieste.
    for i := 0; i < 3; i++ {
        limitatoreARaffica <- time.Now()
    }

    // Ogni 200 millisecondi proveremo ad inviare un
    // nuovo valore al `limitatoreARaffica`, fino ad
    // arrivare al suo limite di 3 richieste.
    go func() {
        for t := range time.Tick(time.Millisecond * 200) {
            limitatoreARaffica <- t
        }
    }()

    // Ora simuleremo 5 richieste al nostro limitatore.
    // Le prime tre potranno godere della capacità del
    // limitatore di eseguire richieste a raffica.
    richiesteARaffica := make(chan int, 5)
    for i := 1; i <= 5; i++ {
        richiesteARaffica <- i
    }
    close(richiesteARaffica)
    for ric := range richiesteARaffica {
        <-limitatoreARaffica
        fmt.Println("richiesta", ric, time.Now())
    }
}
# Eseguendo il nostro programma vedremo il gruppo
# di richieste che verranno gestite ognuna ogni 200
# millisecondi.
$ go run rate-limiting.go
richiesta 1 2016-04-17 19:05:37.736132953 +0200 CEST
richiesta 2 2016-04-17 19:05:37.936138961 +0200 CEST
richiesta 3 2016-04-17 19:05:38.136209943 +0200 CEST
richiesta 4 2016-04-17 19:05:38.336145582 +0200 CEST
richiesta 5 2016-04-17 19:05:38.536120745 +0200 CEST

# Invece, per il nostro secondo gruppo di richieste
# vedremo che le prime tre vengono eseguite
# all'istante, mentre le altre 2 a distanza di 200
# millisecondi l'una dall'altra.
richiesta 1 2016-04-17 19:05:38.536251527 +0200 CEST
richiesta 2 2016-04-17 19:05:38.536266185 +0200 CEST
richiesta 3 2016-04-17 19:05:38.536277665 +0200 CEST
richiesta 4 2016-04-17 19:05:38.736385724 +0200 CEST
richiesta 5 2016-04-17 19:05:38.936385957 +0200 CEST