Limitador de Tasa Distribuido
Un limitador de tasa de ventana deslizante respaldado por Redis para servicios Go escalados horizontalmente.
Este proyecto implementa un limitador de tasa de ventana deslizante que guarda marcas de tiempo de solicitudes en sorted sets de Redis, de modo que cada instancia de la aplicación evalúa el mismo contador compartido. Cada decisión elimina entradas expiradas, cuenta los hits restantes dentro de la ventana activa y registra la solicitud actual con un TTL que limita el crecimiento del almacenamiento.
El diseño es deliberadamente pequeño: Redis aporta ordenamiento casi atómico mediante un pipeline transaccional, mientras Go mantiene una interfaz sincrónica fácil de envolver en handlers HTTP o interceptores RPC. Las solicitudes denegadas eliminan su entrada tentativa después de completar el pipeline, manteniendo la ventana precisa sin coordinación entre clientes.
func Allow(ctx context.Context, rdb *redis.Client, key string, limit int, window time.Duration) (bool, error) {
now := time.Now()
cutoff := now.Add(-window).UnixMilli()
member := strconv.FormatInt(now.UnixNano(), 10)
pipe := rdb.TxPipeline()
pipe.ZRemRangeByScore(ctx, key, "0", strconv.FormatInt(cutoff, 10))
count := pipe.ZCard(ctx, key)
pipe.ZAdd(ctx, key, redis.Z{Score: float64(now.UnixMilli()), Member: member})
pipe.Expire(ctx, key, window)
if _, err := pipe.Exec(ctx); err != nil {
return false, err
}
if count.Val() >= int64(limit) {
_ = rdb.ZRem(ctx, key, member).Err()
return false, nil
}
return true, nil
}