Implementando Limitação de Taxa em Go

Beginner

This tutorial is from open-source community. Access the source code

Introdução

O laboratório demonstra como implementar limitação de taxa (rate limiting) em Go usando goroutines, canais (channels) e tickers.

Limitação de Taxa (Rate Limiting)

O problema é limitar o tratamento de requisições recebidas para manter a qualidade do serviço e controlar a utilização de recursos.

  • Linguagem de programação Go
  • Compreensão básica de goroutines, canais (channels) e tickers
## Executando nosso programa, vemos o primeiro lote de requisições
## sendo tratado uma vez a cada ~200 milissegundos, como desejado.
$ 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

## Para o segundo lote de requisições, servimos as primeiras
## 3 imediatamente por causa da limitação de taxa "burstable",
## então servimos as 2 restantes com atrasos de ~200ms cada.
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

A seguir, o código completo:

// A [_limitação de taxa_](https://en.wikipedia.org/wiki/Rate_limiting)
// é um mecanismo importante para controlar a utilização de recursos
// e manter a qualidade do serviço. Go
// suporta elegantemente a limitação de taxa com goroutines,
// canais (channels) e [tickers](tickers).

package main

import (
    "fmt"
    "time"
)

func main() {

    // Primeiro, vamos analisar a limitação de taxa básica. Suponha
    // que queremos limitar o tratamento de requisições recebidas.
    // Serviremos essas requisições de um canal com o
    // mesmo nome.
    requests := make(chan int, 5)
    for i := 1; i <= 5; i++ {
        requests <- i
    }
    close(requests)

    // Este canal `limiter` receberá um valor
    // a cada 200 milissegundos. Este é o regulador em
    // nosso esquema de limitação de taxa.
    limiter := time.Tick(200 * time.Millisecond)

    // Ao bloquear em uma recepção do canal `limiter`
    // antes de servir cada requisição, nos limitamos a
    // 1 requisição a cada 200 milissegundos.
    for req := range requests {
        <-limiter
        fmt.Println("request", req, time.Now())
    }

    // Podemos querer permitir rajadas curtas de requisições em
    // nosso esquema de limitação de taxa, preservando o
    // limite geral de taxa. Podemos conseguir isso por
    // bufferizando nosso canal limiter. Este canal `burstyLimiter`
    // permitirá rajadas de até 3 eventos.
    burstyLimiter := make(chan time.Time, 3)

    // Preencha o canal para representar a explosão permitida.
    for i := 0; i < 3; i++ {
        burstyLimiter <- time.Now()
    }

    // A cada 200 milissegundos, tentaremos adicionar um novo
    // valor a `burstyLimiter`, até seu limite de 3.
    go func() {
        for t := range time.Tick(200 * time.Millisecond) {
            burstyLimiter <- t
        }
    }()

    // Agora simule mais 5 requisições recebidas. As primeiras
    // 3 delas se beneficiarão da capacidade de rajada
    // de `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())
    }
}

Resumo

O laboratório demonstra como implementar limitação de taxa (rate limiting) em Go usando goroutines, canais (channels) e tickers para controlar a utilização de recursos e manter a qualidade do serviço.