Buenas prácticas de Caching en ASP.NET 4.5.1 - Hacia escalabilidad y alto rendimiento - performance

774 views
Skip to first unread message

Carlos Admirador

unread,
Aug 5, 2015, 4:18:10 PM8/5/15
to AltNet-Hispano
Hola gente del grupo!!!
Considerando mi gran torpeza, y teniendo de base una aplicación  ASP.NET 4.5.1  WebForms Legacy, estaba pensando en utilizar Cache para mejorar el rendimiento-escalabilidad de la aplicación web aspnet.

Por ejemplo, expongo el caso. Se realiza la autenticación (usuario y contraseña). Existe un SqlSiteMapProvider, y a su vez un Membership y RoleProvider. Los usuarios son de tablas propias de SqlServer y algunos datos de Oracle.
Para el objeto "UsuarioDeMiWeb", se define una propiedad que tenga un "permiso-rol", que indique si un botón de la Home (Default.aspx) se mostrará o no. Dicha propiedad es el resultado a una llamada a un "Web Service" externo (WCF).
Existen otros casos similares en la aplicación (opciones de menú que serán visibles o no según ciertas condiciones o llamadas a consultas SQL).

La idea es poder "cachear" ese "resultado de llamada del servicio WCF" por  usuario.

Desde mi gran ignorancia veo que hay un "contexto" para una aplicación ASP.NET: https://msdn.microsoft.com/en-us/library/ms972109.aspx

Puedo tener en cuenta, yo creo:

Session
HttpContext.Current.Session
HttpContext.Current.Cache
HttpRuntime.Cache
HttpContext.Current.Items
System.Web.Hosting.HostingEnvironment.Cache
...
HttpContext.Current.Cache NO ES LO MISMO que  HttpRuntime.Cache

Me quedo con Session o con HttpContext.Current.Cache. Creo que aplica a un usuario. NO SÉ CUÁL puede ser la mejor opción considerando performance y escalabilidad.
Me inclino por Current.Cache si es que no se "comparten" (shared) datos entre usuarios, si el ámbito es para un único usuario.

HttpRuntime.Cache descarto pues creo que aplica a TODOS los usuarios.

Googleando la información es extensa, y para los torpes nos cuesta procesarla. Hace falta una "Guía defnitiva" (al estilo http://www.codeproject.com/Articles/16466/Unraveling-the-Mysteries-of-NET-Configuration)

Puedo tener clases "Helper" para manejar la caché, (recomendaciones??), hay alguna de Walter Poch

http://johnnycoder.com/blog/2008/12/10/c-cache-helper-class/

https://codepm.wordpress.com/2010/09/28/using-c-delegates-with-asp-net-data-caching/

http://stackoverflow.com/questions/4419981/application-end-cannot-access-cache-through-httpcontext-current-cachekey/4422775#4422775

http://michaelkappel.com/examples/CSharp/Cache/HelperCache.htm

https://gist.github.com/wpoch/1031653

http://weblogs.asp.net/zowens/easier-way-to-manage-your-asp-net-cache

Incluso el gurú Hanselman tenía algún "ejemplo", pero nada "definitive guide"
http://www.hanselman.com/blog/TheWeeklySourceCode35ZipCompressingASPNETSessionAndCacheState.aspx

Y buscando más te das con referencias de "escalabilidad", pero hay que tener mucho nivel, experiencia, y tiempo de aprendizaje para ello. IMHO

Omar Al Zabir hace unos años: http://es.slideshare.net/oazabir/scaling-aspnet-websites-to-millions-of-users?next_slideshow=1
De Encosia: http://encosia.com/a-harsh-reminder-about-the-importance-of-debug-false/

Deanohume:
http://www.deanhume.com/Home/BlogPost/faster-mobile-websites---slides/10127
http://www.deanhume.com/Home/PageSpeed

O referencias más avanzadas
http://www.robbagby.com/rest/rest-in-wcf-part-x-supporting-caching-and-conditional-get/

Tess Ferrandez de Microsoft hace años tenía un blog muy avanzado de rendimiento (ya a bajo nivel). Ahora no he encontrado referentes así en Microsoft.

Pueden comentar sus experiencias, su visión, sus lecciones aprendidas y buenas prácticas al respecto, sus ejemplos o aplicaciones asp.net que compartan, sus enlaces delicious o Pocket que compartan, etc ?
Desde ya muchas gracias, gente!!

Si se animan a VANs, Google Hangouts, Webcasts,  yo encantado de ver, callar, escuchar, aprender...

Saludos.
Carlos

Carlos Peix

unread,
Aug 5, 2015, 8:05:16 PM8/5/15
to altnet-hispano
Para el uso que mencionás tenes que usar Session.

Hablando de escalabilidad, también depende de que tipo de escalabilidad necesites. Cual es tu punto crítico? que medidas has tomado como para entender si cachear esa información es necesario?

Pregunto esto porque podría haber escenarios en los cuales guardar esa información en Sesión también atentaría contra la escalabilidad (escalamiento horizontal de servidores web, por ejemplo).

----------------------------------
Carlos Peix

--
Has recibido este mensaje porque estás suscrito al grupo "AltNet-Hispano" de Grupos de Google.
Para anular la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a altnet-hispan...@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a altnet-...@googlegroups.com.
Visita este grupo en http://groups.google.com/group/altnet-hispano.
Para acceder a más opciones, visita https://groups.google.com/d/optout.

Carlos Admirador

unread,
Aug 6, 2015, 12:30:24 PM8/6/15
to AltNet-Hispano
Gracias Carlos! Desde mi desconocimiento, por qué (argumentos) mejor usar Session que HttpContext.Current.Cache ?
No sé porqué me comentaron de evitar utilizar la Session, aunque en esta aplicación Legacy se ha utilizado para paginación de GridView (List<T>)  y otras cosas.

HttpContext.Current.Cache no es recomendable?
 HttpContext.Current.Cache.Add(sUsuario, usu, null, Cache.NoAbsoluteExpiration, new TimeSpan(0, Settings.Default.MinutosCacheUsuarioContexto, 0), CacheItemPriority.NotRemovable, null);

Puntos críticos...tendría que analizarlo bien.

Utilizan la aplicación unos 800 usuarios.

En la autenticación se hacen muchas consultas  para obtener datos del usuario "logado". Aparte del sitemap, también para presentar algunas opciones del menú y controles en la página (Visible true o false) hay que comprobar ciertos permisos específicos.
Estos permisos:
1.) realizan alguna consulta SQL a la base de datos
2.) realzian llamada a un WCF Service externo.

Se puede estar llamando muchas veces (entre 7 y 8 veces) al método 
ObtenerInfoUserPortal, cada vez que se introduce usuario y password y se llama a la página Home.aspx (Default.aspx).

public static UsuarioPortal ObtenerInfoUserPortal(string sUsuario)

        {

            var usu = DAL.SeguridadPortal.DevUsuarioPortal(sUsuario);

            var tienePermiso = ObtenerPermisoAsesor();

            usu.TienePermisoAsesor = tienePermiso;
            usu.TienePermisoABC = ObtenerPermisoABC_Llamando_a_WcfService(sUsuario);

            return usu;

        }

private static bool? ObtenerPermisoAsesor()

        {
                int id= int.MinValue;
                ...
                int? codigoCpc = GetCodigoCPC(id,ConfigPortal.Empresa);
                var campanias = Bll.GetCampaniasPorTipo(codigoCpc.ToString(), "0", id.ToString());
                var campaniaAsesor = campanias.Where(p => p.Codigo.Substring(0, 4) == "1111").ToList();
                return campaniaAsesor.Any();
        }
Gracias de antemano.

Carlos Peix

unread,
Aug 6, 2015, 12:57:01 PM8/6/15
to altnet-hispano
2015-08-06 13:30 GMT-03:00 Carlos Admirador <admirado...@gmail.com>:
Gracias Carlos! Desde mi desconocimiento, por qué (argumentos) mejor usar Session que HttpContext.Current.Cache ?

Porque Cache es para todos los usuarios, Session para solo para uno.
 
No sé porqué me comentaron de evitar utilizar la Session, aunque en esta aplicación Legacy se ha utilizado para paginación de GridView (List<T>)  y otras cosas.

Guardar indiscriminada mente resultados de consultas en la Session no es una buena práctica, mucho menos si guardas datos que requieren paginación, de donde deduzco que serán muchos.

Hay otro problema y es que, si haces eso, esa pantalla no soportará multples instancias para el mismo usuario mostrando cada una información diferente.

HttpContext.Current.Cache no es recomendable?
HttpContext.Current.Cache.Add(sUsuario, usu, null, Cache.NoAbsoluteExpiration, new TimeSpan(0, Settings.Default.MinutosCacheUsuarioContexto, 0), CacheItemPriority.NotRemovable, null);

Cache es, mas bien, para daros globales a la aplicación, es decir, para todos los usuarios por igual. Además es muy util el mecanismo de expiración y también el WeakReference.
 
Puntos críticos...tendría que analizarlo bien.

Utilizan la aplicación unos 800 usuarios.

En la autenticación se hacen muchas consultas  para obtener datos del usuario "logado". Aparte del sitemap, también para presentar algunas opciones del menú y controles en la página (Visible true o false) hay que comprobar ciertos permisos específicos.
Estos permisos:
1.) realizan alguna consulta SQL a la base de datos
2.) realzian llamada a un WCF Service externo.

Otra opción es almacenar esos datos en la cookie siempre y cuanto sean de pequeño tamaño y no haya restricciones de seguridad muy severas.

juan ladetto

unread,
Aug 6, 2015, 2:24:58 PM8/6/15
to altnet-...@googlegroups.com
Hola a todos.
Pequeños comentarios:
En lo que al usuario respecta el IPrincipal tiene sus limitaciones; nosotros guardamos la información de un usuario en la session del mismo (perfil, roles que pueden asumir, etc), para escalar horizontalmente utilizamos mongodb aunque las pruebas que hicimos con redis también funcionaron a la perfección como session provider (utilizamos redis como cache de queries que pueden ser cacheadas aunque el ttl sean 10 segundos).
En el cache se guardan muchísimas cosas y utilizar redis/mongo hacen que ninguna aplicación escale (los recursos html, css, etc) se guardan en cache (no me pregunten porque).

Además viendo el código de arriba mi primer recomendación sería que puedas meter en cache esa info (utilizando un mecanismo propio de uds) y utilizando redis o algún otro key-value store para almacenar esos queries. COn esto podrías hacer que si un objeto tiene que vivir 4 minutos como máximo porque los roles cambian puedan hacerlo.

Algo así tenemos nosotros implementado (traer los últimos tweets publicados):
            var connection = Site.Helpers.OpenRedisConnection.ConnectToPooledRedis();
            var tweets = connection.Get<IEnumerable<TwitterStatus>>(twitterRedisKey);
            if (tweets == null)
            {
                var service = new TwitterService(ConsumerKey, ConsumerSecret);
                service.AuthenticateWith(AccessToken, AccessTokenSecret);
                tweets = service.ListTweetsOnUserTimeline(new ListTweetsOnUserTimelineOptions() { Count = 15 });
                connection.Put<IEnumerable<TwitterStatus>>(twitterRedisKey, tweets, 1200);
            }

Espero que sirva

Saludos
Juan

Carlos Admirador

unread,
Aug 7, 2015, 11:00:11 AM8/7/15
to AltNet-Hispano
Muchas gracias Juan por la aportación!!!. Un uso muy aclarador de TweetSharp y la Cache.

De Redis ni idea de nada, torpeza otra vez. Me surgen dudas, y no sé si el grupo tiene lecciones aprendidas y patterns&practices al respecto.

http://www.codeproject.com/Articles/636730/Distributed-Caching-using-Redis
http://www.programering.com/a/MDM2kzMwATM.html
http://maxivak.com/getting-started-with-redis-and-asp-net-mvc-under-windows/

Por ejemplo, una duda 1: empezamos con la instalación de Redis (SErver) en los servidores (ya toca tratar con Sistemas: instalar, configurar, abrir puertos??). En Servidores Windows 2008 R2 cómo instalar y si se instala como servicio windows. Además, de la correcta configuración de Redis.

Otra duda 2, cómo realizar la instalación de Redis Server en el equipo de desarrollo Windows 8.1 (mi localhost), y tenerlo preparado para pruebas (start service Redis, stop service Redis, etc..)

duda 2a: Para instalar en mi equipo de desarrollo, quizá fácil con Chocolatey: http://geekindulgence.com/install-redis-as-a-windows-service-using-chocolatey/
duda 2b: Para instalar en los servidores Win2008R2, proporcionar a compañeros de Sistemas un mecanismo fácil para la instalación y configuración de Redis Server.

Otra duda 3, selección de un Cliente C# para Redis
http://redis.io/clients#c

Y la duda 4, uso de buenas prácticas del cliente Redis (problemas con conexiones, ConnectToPooledRedis ??, pool, cerrar conexiones Redis ?? )

No sé si el grupo puede aportar algo de sus experiencias.

Lo que ya veo a otro nivel son conceptos como mongodb, redis como session provider, "cache de queries" ... escapa a mi escaso entendimiento

Gracias de antemano!

Carlos Peix

unread,
Aug 7, 2015, 11:19:21 AM8/7/15
to altnet-hispano
Carlos,

La experiencia de Juan es super valiosa (responsable técnico de un sitio con MUCHO movimiento) pero creo que sería un error que utilices sus consejos sin saber si son necesarios en tu contexto.

Por eso te preguntaba que indicadores tenes de que necesitas esa optimización, pregunta que quedó en el olvido, aparentemente.

----------------------------------
Carlos Peix

Carlos Admirador

unread,
Aug 7, 2015, 11:49:34 AM8/7/15
to AltNet-Hispano
Sí, muy valiosa (increiblemente valiosa) las experiencias "reales" de aplicaciones que están en entornos de producción, y más aún si tiene mucho tráfico. Al menos tener los conocimientos y ya evaludar desde mi ignorancia aplicarlos y si encajan (todo es cuestión también de probar en los entornos de desarrollo de la empresa y tener ciertas pautas). Y agradecer ENORMEMENTE a Juan que lo comparta.

El indicador: En la navegación entre páginas de mi aplicación asp.net legacy se nota que va "lenta", como apreciación, entre postbacks y llamadas a otras páginas, hasta que muestra el contenido en la página (renderizado).
Estoy viendo cómo poder trazar (no sé cómo si EWT, Ent.Lib, Log4Net, NLog, Serilog, ...) el flujo entre llamadas, por dónde va pasando y a ser posible cálculo de tiempos sobre todo el acceso a datos (sql profiler descartado porque no podemos contar con sistema ni admin.BD para esto, así que toca trazar Trace.WriteLine, Log.Write, etc ).

Saludos,
CArlos.

juan ladetto

unread,
Aug 7, 2015, 12:32:46 PM8/7/15
to altnet-...@googlegroups.com
Carlos... le hago caso a Carlos Peix (ya tendré la oportunidad de encontrarme con él nuevamente) y te cuento como hacemos nosotros para entender donde tenemos los "cuellos de botella":
- Utilizamos postsharp 4.0 y un decorator.
El código es algo así como: 

    public class IOLTraceAttribute : OnMethodBoundaryAspect
    {
        private readonly int miliseconds;
        private string enableProfiling;

        public IOLTraceAttribute(int miliseconds)
        {
            this.miliseconds = miliseconds;
        }

        public override void OnEntry(MethodExecutionArgs args)
        {
            this.enableProfiling = ConfigurationManager.AppSettings["EnableProfiling"];
            if (!string.IsNullOrEmpty(this.enableProfiling) && this.enableProfiling.ToLowerInvariant() == "true")
            {
                Profiler.Start();
            }
        }

        public override void OnExit(MethodExecutionArgs args)
        {
            if (!string.IsNullOrEmpty(this.enableProfiling) && this.enableProfiling.ToLowerInvariant() == "true")
            {
                int count = Profiler.Stop();
                if (count > this.miliseconds)
                {
                    TraceLogger.Log(args.Method.DeclaringType.Name, args.Method.Name, args.Arguments, count);
                }
            }
        }
    }
 y TraceLogger.log es un wrapper sobre log4net que termina guardando como profile INFO lo que esto produce.

Este decorator lo tienen todos los posibles puntos problemáticos y todos aquellos que queremos medir (casi toda la aplicación). Nuestro web.config tiene 2 puntos de control (un flag de profile prendido y otro si log4net loguea esos mensajes).
  <log4net>
    <root>
      <level value="ALL"/>
...
      <appender-ref ref="InfoLogFileAppender"/>
    </root>
y en InfoLogFileAppender escuchamos o no esto.

Sobre redis librería: utilizar la librería de stackoverflow https://github.com/StackExchange/StackExchange.Redis, se encarga sola del pool y es a mi modo de ver la mejor actualmente para .net :)

Sobre redis en dev: redis-server en la máquina del developer y listo (habla sobre el puerto 6329 si no recuerdo mal), 
Sobre redis en prod: montarlo de ser posible sobre linux sino como servicio sobre windows.


Lo seguimos... saludos
Juan

Leonardo Micheloni

unread,
Aug 7, 2015, 6:52:37 PM8/7/15
to altnet-hispano
Solo para meter ruido: nosotros hemos usado ElasticCache de Amazon (es casi un memcached), eso sí, para Windows no te lo recomiendo, funciona, pero al menos cuando lo hicimos (hace dos años) era pésimo el rendimiento en comparación con Linux, pero servía para desarrollar en Windows y desplegar en Amazon, también tuvimos que tocar el driver de C# porque tenía algún bug (poco alentador mi consejo como verás) pero bueno, una vez que funcionó quedó de pelos, al día de hoy sigue funcionando.
@leomicheloni Microsoft MVP

juan ladetto

unread,
Aug 8, 2015, 10:30:45 AM8/8/15
to altnet-...@googlegroups.com
Leo/resto.
memcached actualmente es más lento que redis y ofrece menos posibilidades de escalamiento. Elasticcache ahora soporta redis como opción.
 
Redis/mongodb no tienen la misma performance sobre linux que sobre windows, Mongodb utiliza memory mapped files y redis utiliza algo muy similar (esto lo hace a nivel OS y sobre windows no es tan performante como sobre linux).

Abzs

Leonardo Micheloni

unread,
Aug 8, 2015, 11:01:48 AM8/8/15
to altnet-...@googlegroups.com
Excelente información, gracias Juan!

De: juan ladetto
Enviado el: ‎08/‎08/‎2015 11:30
Para: altnet-...@googlegroups.com
Asunto: Re: [altnet-hispano] Buenas prácticas de Caching en ASP.NET 4.5.1 - Hacia escalabilidad y alto rendimiento - performance

[No se incluye el mensaje original completo.]

Carlos Admirador

unread,
Aug 14, 2015, 7:39:14 AM8/14/15
to AltNet-Hispano
Gracias Juan! Grandiosa tu respuesta, sobre todo, basado en una experiencia real de sitio con mucho tráfico, y ahí se ven esos conocimientos dónde atajar los "cuellos de botella".

La clase Profiler es como un StopWatch ?

                Profiler.Start();
                int count = Profiler.Stop();

Yo me pierdo en todos los detalles, veo que aparte de Redis, ElasticCache de Amazon, Memcached, y también aplica el AppFabric Caché de Microsoft (algo había leido).
mongodb también tiene dicha funcionalidad, o va en combinación con Redis?

Concluyo que StackExchange.Redis es la recomendación en .NET, y para llegar a máximo rendimiento y escalabilidad con Redis (y con mongodb,  ElasticCache, ...)  mejor montarlo con Linux. Aquí en la empresa lo haríamos en Windows si se deciden a ello.

Leo, si el ruido es de proyectos y experiencias reales de unos cracks como vosotros, parafrasenado a sr.Rajoy, viva el ruido !!! ElasticCache de Amazon  tiene driver de C# (y en Windows), a día de hoy, cuál sería el recomendado?

Pensando en voz alta desde mi torpeza, no sé si habrá clase CacheHelper que se abstraiga si se utiliza HttpCurrent.Cache, o Redis, o AppFabric...sobre todo, pensando en control de errores, si no existe servidorRedis o está caído o errores Timeout, que utilice HttpCurrent.Cache

Gracias de corazón con los comentarios!
Saludos gente!
Carlos

juan ladetto

unread,
Aug 14, 2015, 8:21:41 AM8/14/15
to altnet-...@googlegroups.com
Carlos...
va intercalado

2015-08-14 8:39 GMT-03:00 Carlos Admirador <admirado...@gmail.com>:
Gracias Juan! Grandiosa tu respuesta, sobre todo, basado en una experiencia real de sitio con mucho tráfico, y ahí se ven esos conocimientos dónde atajar los "cuellos de botella".

La clase Profiler es como un StopWatch ?

                Profiler.Start();
                int count = Profiler.Stop();

Sip... cualquier cosa que te permita "mirar" y obtener información sobre posibles cuellos de botella (lo que les comenté anteriormente fue lo que nosotros econtramos como solución). 
Yo me pierdo en todos los detalles, veo que aparte de Redis, ElasticCache de Amazon, Memcached, y también aplica el AppFabric Caché de Microsoft (algo había leido).
AppFrabric Caché está bueno y tiene las bondades de redis y memcached. Por ahí si lo van a hacer sobre Windows puede ser otra solución a mirar.
mongodb también tiene dicha funcionalidad, o va en combinación con Redis?
Mongodb es otro tipo de base de datos no relacional (no lo utilizaría para caching) 

Concluyo que StackExchange.Redis es la recomendación en .NET, y para llegar a máximo rendimiento y escalabilidad con Redis (y con mongodb,  ElasticCache, ...)  mejor montarlo con Linux. Aquí en la empresa lo haríamos en Windows si se deciden a ello.
Para mi StackExchange.Redis es la recomendación actual (nosotros para mongodb utilizamos el driver de mongodb) 

Leo, si el ruido es de proyectos y experiencias reales de unos cracks como vosotros, parafrasenado a sr.Rajoy, viva el ruido !!! ElasticCache de Amazon  tiene driver de C# (y en Windows), a día de hoy, cuál sería el recomendado?
ElasticCache si no vas a montar la solución en amazon no lo utilizaría (latencia a amazon desde donde hostees). 

Pensando en voz alta desde mi torpeza, no sé si habrá clase CacheHelper que se abstraiga si se utiliza HttpCurrent.Cache, o Redis, o AppFabric...sobre todo, pensando en control de errores, si no existe servidorRedis o está caído o errores Timeout, que utilice HttpCurrent.Cache
+1 a la abstracción e inyección pero guarda con httpcurrent.cache que como ya les compartí anteriormente va de todo ahí y puede ser un nuevo cuello de botella (nosotros inicialmente persistimos httpcurrent.cache en redis y no te das una idea la cantidad de cosas que se guardan y se buscan permanentemente). Yo no utilizaría httpcurrent.cache con ninguna solución anterior (dejaría la solución que viene out of the box, memoria).

Saludos
Juan

Gracias de corazón con los comentarios!
Saludos gente!
Carlos

El sábado, 8 de agosto de 2015, 17:01:48 (UTC+2), Leonardo Micheloni escribió:
Excelente información, gracias Juan!

De: juan ladetto
Enviado el: ‎08/‎08/‎2015 11:30
Para: altnet-...@googlegroups.com
Asunto: Re: [altnet-hispano] Buenas prácticas de Caching en ASP.NET 4.5.1 - Hacia escalabilidad y alto rendimiento - performance

Leo/resto.
memcached actualmente es más lento que redis y ofrece menos posibilidades de escalamiento. Elasticcache ahora soporta redis como opción.
 
Redis/mongodb no tienen la misma performance sobre linux que sobre windows, Mongodb utiliza memory mapped files y redis utiliza algo muy similar (esto lo hace a nivel OS y sobre windows no es tan performante como sobre linux).

Abzs

2015-08-07 19:52 GMT-03:00 Leonardo Micheloni <leonardogabr...@gmail.com>:
Solo para meter ruido: nosotros hemos usado ElasticCache de Amazon (es casi un memcached), eso sí, para Windows no te lo recomiendo, funciona, pero al menos cuando lo hicimos (hace dos años) era pésimo el rendimiento en comparación con Linux, pero servía para desarrollar en Windows y desplegar en Amazon, también tuvimos que tocar el driver de C# porque tenía algún bug (poco alentador mi consejo como verás) pero bueno, una vez que funcionó quedó de pelos, al día de hoy sigue funcionando.

Leonardo Micheloni

unread,
Aug 14, 2015, 10:48:38 AM8/14/15
to altnet-hispano
Como dice Juan, nuestra experiencia con Elastic cache fue un sitio grande (millones de request por día) pero dentro de Amazon, es decir, las VM Windows corriendo servicios que apuntaban a Elastic cache y algunas app de Linux que también usaban datos de ahí. Es decir, no lo usaría desde afuera de EC2.
 Sí, hay un driver para C#, como dije antes, tuvimos que tocar algo a mano por una limitación que no me acuerdo (te lo puedo averiguar sin problemas) y era transparente probar local con memcached en Windows y desplegarlo a Amazon, no había problemas.
--
@leomicheloni Microsoft MVP

Kiquenet

unread,
Aug 21, 2015, 11:03:05 AM8/21/15
to AltNet-Hispano
En este blog, donde explican como montar tu propio servidor REDIS en windows y como instalar y configurar el paquete nuget con las librerías necesarias.

En este caso, sería cambiarlo por StackExchange.Redis.

Entiendo que la clase Profiler es multi-threaded, multi-user, pues varios usuarios a la vez conectados imagino pueden afectar a la medición de tiempos en esos cuellos de botella.

Ariel Piñeiro

unread,
Aug 21, 2015, 12:59:59 PM8/21/15
to altnet-...@googlegroups.com
Redis anda muy bien, les recomiendo también la versión 3 de ServiceStack (free). También existe un fork open-source de la v3.

No obstante StackExchange es una buena alternativa.

--

Walter Poch

unread,
Aug 21, 2015, 3:47:52 PM8/21/15
to altnet-...@googlegroups.com
Buenas, recién tengo tiempo de ver esto.

Carlos, lo que yo haría es mover todo lo costoso de calcular (Roles, Permisos que por lo que entendí los obtene por remote calls) para que se ejecuten una única vez en el login del usuario. Esto si es que el negocio te lo permite, es decir, ante un cambio de permisos/roles el usuario tendría que volver a iniciar sesión, caso contrario deberías poder recalcularlo bajo pedido. Esta información dependería de la sesión y como bien decía Carlos Peix debe ir en el objeto Session (Cache es compartida, y tenés que tener cuidado con las cache keys).
Luego de esto, habría que ver donde estas guardando tu sesión, yo lo movería a un session provider basado en Redis (hosteado en Linux). Esto te permitirá hacer escalabilidad horizontal, agregando web servers.

Ademas de todo esto, revisar muy bien que objetos estas guardando en Session, por ejemplo la paginación deberías guardarla del lado cliente.

Una vez que tengas eso analizado, yo empezaría a mirar el tamaño de los PostBacks, ya que muchas veces (me ha pasado) terminan superando 1MB de transferencia, y por mas que optimices, eso tiene que enviarse y recibirse en cada acción que hagas. Aquí entraría revisar los assets de la aplicación ver de minimizar, comprimir, bundling y cache headers.

Luego lo que comentaban de usar PostSharp, cuando me tocó un proyecto de 10 años WebForms, lo primero que hice fue poner un aspect similar al que comentaron (casi idéntico). Lo aplique usando MultiCast en los assemblies que tenían interfaces con sistemas externos, y acceso a la base de datos. De esta forma luego fuimos analizando los cuellos de botella, y viendo si esas llamadas podían ser optimizadas. Esto puede ser en el sistema externo, o reducir la cantidad de llamadas mediante el uso de cache; en este caso si irían al objeto HttpContext.Current.Cache pero siempre teniendo mucho cuidado con la KEY, e invalidación de cache.

Bueno espero te sirva de algo, un abrazo!

Kiquenet

unread,
Sep 3, 2015, 5:32:18 PM9/3/15
to AltNet-Hispano

De StackExchange.Redis una guía rápida y fácil para empezar a usarlo (paquete nuget y configuración, y pequeño ejemplo de código fuente)

Y una referencia de Isaac Ojeda, para instalar Redis en Windows

"Redis oficialmente no mantiene una versión de éste para Windows (su página oficial lo dice) pero al ser un proyecto open source, existe un fork mantenido por MSOpenTech donde existe la posibilidad de correr Redis en Windows."

Instalación con gestor de paquetes Chocolatey. También hace uso del paquete de Nuget llamado StackExchange.Redis:
Y añade un ejemplo interesante de código, con una clase Helper, no sé si aplicable a proyectos reales y sobre todo proyectos reales de gran tráfico (en millones).

Sin duda, una clase Wrapper-Helper facilitaría el uso, y como se comentaba en el hilo, no sé si tendrá sentido usar HttpContext.Current.Cache si Redis está caído, manteniendo un interfaz constante, independientemente que se guardara en Redis , o AppFabric, o HttpContext.Current.Cache.

Carlos Admirador

unread,
Sep 4, 2015, 10:31:11 AM9/4/15
to AltNet-Hispano
Hola gente !!! Muchísimasss gracias por los comentarios! al gran Juan, Leo, Kiquenet, Ariel, y Walter poch. Desde mi gran torpeza leyendo con detenimiento me surgen varias dudas.

1) Cómo obtener el tamaño de los postbacks ? algún code snippet o herramienta para ello ? (cuál es el truco ? :-) )

2) De PostSharp (o el Profiler), se comentó de aplicarlo usando "MultiCast", ahí ya me pierdo.

3) No entiendo nada (por torpeza) el concepto "persistir httpcurrent.cache en Redis". En mi limitada capacidad llego a que quiero guardar strings u objetos en "Cache"

Un pseudo código rápido
Con httpcurrent.cache:


private static bool StoreData1(string key, string value)
{
    HttpCurrent.Cache[key] = value;
    return true;
}

private static string GetData1(string key)
{
    return HttpCurrent.Cache[key];
}


Con Redis


private static bool StoreData2(string key, string value)
{
    return conexionARedis.StringSet(key, value);
}

private static string GetData2(string key)
{
    return conexionARedis.StringGet(key);
}

La idea de la abstracción sería algo así:


private static bool StoreData(string key, string value)
{
   if (hayRedisActivo) return StoreData1(key, value),
   return StoreData2(key, value);
}

private static string GetData1(string key)
{
 if (hayRedisActivo) return GetData1(key);
   return GetData2(key);
}

siendo hayRedisActivo una variable boolean (static?) que tiene un valor de configuración (app.config - web.config) o la respuesta OK o KO a un telnet ServidorRedis: Puerto

En la referencia anterior, también aparece  "All you need to know about Redis" pero aplicado a Azure
http://tostring.it/2015/03/05/all-you-need-to-know-about-redis/

Ahí utilizan variables static para la conexión a redis:

 private static ConnectionMultiplexer connectionMultiplexer;
        private static IDatabase database;


y se configura así:


private static void Configure() { //use locally redis installation var connectionString = string.Format("{0}:{1}", "127.0.0.1", 6379); //use azure redis installation var azureConnectionString = string.Format("{0}:{1},ssl=true,password={2}", "imperugo-test.redis.cache.windows.net", 6380, "Azure Primary Key"); connectionMultiplexer = ConnectionMultiplexer.Connect(connectionString); database = connectionMultiplexer.GetDatabase(); }


El tema de variables static y aplicaciones Web hay que tener cuidado, y en cuanto a rendimiento y escalabilidad no sé si es buena práctica mantener una conexión static a Redis. Vamos no veo el patrón de implementación a seguir Redis + App. Web. No lo veo igual que una aplicación de consola (.exe).

Muchas gracias gente!
Saludos
Carlos

Carlos Admirador

unread,
Nov 4, 2015, 2:28:27 PM11/4/15
to AltNet-Hispano

Ariel Piñeiro

unread,
Nov 5, 2015, 9:25:03 AM11/5/15
to altnet-...@googlegroups.com
Carlos,
     mi humilde opinión evaluaría la posibilidad de delegar la responsabilidad de cachear a un servidor Web a aplicaciones cómo




En mayor o menor medida se pueden utilizar con el objetivo de cachear y cada una por separado tiene un valor agregado diferente entre sí. El rendimiento es infinitamente superior al cache del IIS, además permite liberar la carga de CPU entre otras cosas, la mayoría de las plataformas como servicios brinda una capa frontal por delante de tu servidor web e incluso permite balancear carga.

Saludos,
Ari.-

Carlos Admirador

unread,
Nov 5, 2015, 4:18:21 PM11/5/15
to AltNet-Hispano
Gracias Ariel.
He visto que Nginx tiene instalable en Windows. Varnish y Squid solo para Linux?
Entiendo que son servidores HTTP que pueden también cachear. Y la curva de aprendizaje, desde mi gran ignorancia, es ardúa.

Redis he visto documentación y paso a paso como éste
https://balusoft.net/2015/08/27/como-usar-redis-desde-windows-y-c-visual-studio-2015/

Se puede instalar en Windows Server 2008 R2 y existe un API en C# para utilizarlo, además variedad de ejemplos en github. Para torpes como yo, veo la opción más asequible, al ser mucho menor la curva de aprendizaje. Con seguir ese post de Isaac Ojeda facilita mucho y alguna otra referencia más.

Saludos gente!
Carlos

Ariel Piñeiro

unread,
Nov 12, 2015, 9:53:15 AM11/12/15
to altnet-...@googlegroups.com
Carlos,
     estás mezclando temas Redis por lo general se utiliza para cachear otras como cache se segundo nivel, un endpoint, pero no modifica headers ni mucho menos, todo es a mano.

Los otros son mas a nivel HTTP, arriba de tus servicios.



Saludos,
Ari.-

Preguntón Cojonero Cabrón

unread,
Dec 4, 2017, 4:46:29 PM12/4/17
to AltNet-Hispano
Aplaudo código real world utilizado en proyecto s reales en Producción. Así se aprende más (mejor).


El jueves, 6 de agosto de 2015, 20:24:58 (UTC+2), juan escribió:
Reply all
Reply to author
Forward
0 new messages