Implementando la limitación de velocidad en Go

Beginner

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

Introducción

Esta demostración muestra cómo implementar la limitación de velocidad en Go utilizando gorutinas, canales y temporizadores.

Limitación de velocidad

El problema consiste en limitar el procesamiento de solicitudes entrantes para mantener la calidad del servicio y controlar la utilización de recursos.

  • Lenguaje de programación Go
  • Conocimiento básico de gorutinas, canales y temporizadores
## Al ejecutar nuestro programa, vemos que el primer lote de solicitudes
## se procesa una vez cada ~200 milisegundos, como se esperaba.
$ go run rate-limiting.go
solicitud 1 2012-10-19 00:38:18.687438 +0000 UTC
solicitud 2 2012-10-19 00:38:18.887471 +0000 UTC
solicitud 3 2012-10-19 00:38:19.087238 +0000 UTC
solicitud 4 2012-10-19 00:38:19.287338 +0000 UTC
solicitud 5 2012-10-19 00:38:19.487331 +0000 UTC

## Para el segundo lote de solicitudes, atendemos las primeras
## 3 inmediatamente debido a la limitación de velocidad con ráfaga,
## luego atendemos las 2 restantes con retrasos de ~200 ms cada una.
solicitud 1 2012-10-19 00:38:20.487578 +0000 UTC
solicitud 2 2012-10-19 00:38:20.487645 +0000 UTC
solicitud 3 2012-10-19 00:38:20.487676 +0000 UTC
solicitud 4 2012-10-19 00:38:20.687483 +0000 UTC
solicitud 5 2012-10-19 00:38:20.887542 +0000 UTC

A continuación se muestra el código completo:

// La [_limitación de velocidad_](https://en.wikipedia.org/wiki/Rate_limiting)
// es un mecanismo importante para controlar la utilización de recursos
// y mantener la calidad del servicio. Go admite elegantemente la limitación
// de velocidad con gorutinas, canales y [temporizadores](tickers).

package main

import (
    "fmt"
    "time"
)

func main() {

    // Primero veremos la limitación de velocidad básica. Supongamos
    // que queremos limitar nuestro procesamiento de solicitudes entrantes.
    // Atenderemos estas solicitudes a partir de un canal con el
    // mismo nombre.
    solicitudes := make(chan int, 5)
    for i := 1; i <= 5; i++ {
        solicitudes <- i
    }
    close(solicitudes)

    // Este canal `limitador` recibirá un valor cada 200 milisegundos.
    // Este es el regulador en nuestro esquema de limitación de velocidad.
    limitador := time.Tick(200 * time.Millisecond)

    // Al bloquear la recepción del canal `limitador` antes de atender
    // cada solicitud, nos limitamos a 1 solicitud cada 200 milisegundos.
    for req := range solicitudes {
        <-limitador
        fmt.Println("solicitud", req, time.Now())
    }

    // Es posible que queramos permitir ráfagas cortas de solicitudes
    // en nuestro esquema de limitación de velocidad mientras se
    // conserva la limitación de velocidad global. Esto se puede
    // lograr mediante el almacenamiento en búfer del canal limitador.
    // Este canal `limitadorRáfaga` permitirá ráfagas de hasta 3 eventos.
    limitadorRáfaga := make(chan time.Time, 3)

    // Llena el canal para representar la ráfaga permitida.
    for i := 0; i < 3; i++ {
        limitadorRáfaga <- time.Now()
    }

    // Cada 200 milisegundos intentaremos agregar un nuevo valor
    // a `limitadorRáfaga`, hasta su límite de 3.
    go func() {
        for t := range time.Tick(200 * time.Millisecond) {
            limitadorRáfaga <- t
        }
    }()

    // Ahora simula 5 solicitudes entrantes más. Las primeras
    // 3 de estas se beneficiarán de la capacidad de ráfaga de
    // `limitadorRáfaga`.
    solicitudesRáfaga := make(chan int, 5)
    for i := 1; i <= 5; i++ {
        solicitudesRáfaga <- i
    }
    close(solicitudesRáfaga)
    for req := range solicitudesRáfaga {
        <-limitadorRáfaga
        fmt.Println("solicitud", req, time.Now())
    }
}

Resumen

Esta demostración muestra cómo implementar la limitación de velocidad en Go utilizando gorutinas, canales y temporizadores para controlar la utilización de recursos y mantener la calidad del servicio.