4 formas de mejorar el rendimiento de ASP.NET en cargas máximas

 

Introducción

ASP.NET se está volviendo muy popular para desarrollar aplicaciones web y muchas de estas aplicaciones son de naturaleza de alto tráfico y sirven a millones de usuarios. Como resultado, estas aplicaciones tienen un gran impacto en los negocios y, por lo tanto, son muy importantes.

Curiosamente, la arquitectura de la aplicación ASP.NET es muy escalable en el nivel de la aplicación. Y, el protocolo HTTP también es apátrida. Ambos significan que puede ejecutar su aplicación ASP.NET en una granja web con equilibrio de carga donde cada solicitud HTTP se enruta al servidor web más apropiado. Esto le permite agregar fácilmente más servidores web a su granja web a medida que aumenta el tráfico de usuarios. Y esto hace que su nivel de aplicación ASP.NET sea muy escalable. Pero, ¿qué quiero decir con escalabilidad aquí?

La escalabilidad es esencialmente la capacidad de ofrecer un alto rendimiento incluso bajo cargas máximas. Por lo tanto, si el tiempo de respuesta de la página de su aplicación ASP.NET es muy rápido con 10 usuarios y se mantiene tan rápido con 100,000 XNUMX usuarios, entonces su aplicación ASP.NET es escalable. Pero, si su tiempo de respuesta de ASP.NET se ralentiza a medida que aumenta la cantidad de usuarios, entonces su aplicación no es escalable.

 

El problema: cuellos de botella de escalabilidad

A pesar de una arquitectura muy escalable en el nivel de la aplicación, las aplicaciones ASP.NET de hoy en día se enfrentan a importantes cuellos de botella de escalabilidad. Estos cuellos de botella están ocurriendo en cuatro áreas diferentes de la siguiente manera:

  1. Base de datos de aplicaciones
  2. Almacenamiento de estado de sesión ASP.NET
  3. ASP.NET View State
  4. Ejecución de página ASP.NET para salida estática

Permítanme explicar cada uno con más detalle a continuación.

 

Base de datos de aplicaciones

La base de datos de aplicaciones como SQL Server u Oracle se convierte rápidamente en un cuello de botella de escalabilidad a medida que aumenta la carga de transacciones. Esto sucede porque aunque puede escalar el nivel de la base de datos comprando un servidor de base de datos más potente, no puede escalar agregando más servidores al nivel de la base de datos. Por ejemplo, es muy común ver de 10 a 20 servidores en el nivel de la aplicación, pero no puede hacer lo mismo en el nivel de la base de datos.

 

Almacenamiento de estado de sesión ASP.NET

Además, el estado de sesión de ASP.NET debe almacenarse en algún lugar. Y, las opciones listas para usar proporcionadas por Microsoft son InProc, StateServer y SqlServer. Desafortunadamente, las tres opciones tienen problemas importantes de rendimiento y escalabilidad. InProc y StateServer lo obligan a usar sesiones pegajosas y enviar todas las solicitudes HTTP en el mismo servidor donde se creó la sesión. Si configura StateServer como un servidor independiente para evitar sesiones pegajosas, entonces StateServer se convierte en un único punto de falla y su rendimiento también se convierte en un problema importante. Y, SqlServer almacena sesiones ASP.NET en la base de datos de SQL Server como BLOB. Y existen serios problemas de rendimiento y escalabilidad con este enfoque.

 

ASP.NET View State

ASP.NET View State es una cadena oculta codificada (a menudo de 100 KB de tamaño) que se envía al navegador del usuario como parte de la respuesta HTTP. El navegador no hace nada con él y lo devuelve al servidor web en caso de una devolución de HTTP. Esto ralentiza la respuesta de la página ASP.NET, aumenta la carga de las tarjetas de red del servidor web y también consume una gran cantidad de ancho de banda adicional. Y, como saben, el ancho de banda no es barato.

 

Ejecución de página ASP.NET para salida estática

Finalmente, ASP.NET framework ejecuta una página ASP.NET contra una solicitud de usuario, incluso si la salida de la página no cambia con respecto a la solicitud anterior. Esto puede estar bien en entornos de transacciones bajas. Pero en un entorno de muchas transacciones en el que ya se están llevando todos los recursos al límite, esta ejecución adicional puede volverse bastante costosa y un cuello de botella de escalabilidad.

Como dice el dicho “la fuerza de cualquier cadena es tan fuerte como su eslabón más débil”. Por lo tanto, siempre que haya cuellos de botella de escalabilidad en cualquier lugar del entorno de la aplicación ASP.NET, toda la aplicación se ralentiza e incluso se detiene.

E, irónicamente, esto sucede bajo cargas máximas cuando se realizan los niveles más altos de actividad comercial. Por lo tanto, el impacto de cualquier ralentización o tiempo de inactividad es mucho más costoso para su empresa.

ASP.NET enfrenta cuellos de botella de escalabilidad
Figura 1: ASP.NET enfrenta cuellos de botella de escalabilidad
 

NoSQL Database no es la respuesta

NoSQL database El movimiento comenzó como resultado de los problemas de escalabilidad en las bases de datos relacionales. NoSQL database divide los datos en varios servidores y le permite escalar horizontalmente al igual que el nivel de la aplicación.

Pero, NoSQL database requiere que abandone su base de datos relacional y coloque sus datos en un NoSQL database. Y esto es más fácil decirlo que hacerlo por una serie de razones y, de hecho, no es posible en muchos casos.

NoSQL databases no tiene la misma capacidad de gestión y búsqueda de datos que las bases de datos relacionales y quiere que almacene datos de una manera totalmente diferente a la relacional. Además, el ecosistema que rodea a las bases de datos relacionales es demasiado fuerte para que la mayoría de las empresas lo abandonen.

Como resultado, NoSQL databaseLos s son útiles solo cuando se trata de datos no estructurados. Y, la mayoría de las aplicaciones ASP.NET manejan datos de negocios predominantemente estructurados y aptos para bases de datos relacionales. Como resultado, estos datos no se pueden mover a un NoSQL database fácilmente.

E, incluso aquellos que terminan usando un NoSQL database hacerlo para un pequeño subconjunto de sus datos totales que pueden considerarse no estructurados. Y, usan NoSQL database junto con su base de datos relacional existente.

Por lo tanto, la mayoría de las veces necesitará vivir con su base de datos relacional y encontrar otra solución para sus problemas de escalabilidad. Afortunadamente, hay una solución muy viable y la discutiré a continuación.

 

La solución: caché distribuida en memoria

La solución a todos los problemas mencionados anteriormente es usar caché distribuida en memoria en la implementación de su aplicación como NCache. NCache es un Caché distribuida de código abierto para .NET que es extremadamente rápido y linealmente escalable. Piense en ello como un almacén de objetos en memoria que también se distribuye. Estar en memoria lo hace extremadamente rápido y estar distribuido lo hace linealmente escalable.

Lo bueno de una caché distribuida en memoria como NCache es que no le pide que deje de usar su base de datos relacional existente. Puede usar la memoria caché encima de su base de datos relacional porque la memoria caché elimina todos los cuellos de botella de escalabilidad de la base de datos relacional.

NCache Proporciona escalabilidad lineal
Figura 2: NCache Proporciona escalabilidad lineal

Entonces, ¿cómo es una memoria caché distribuida en memoria? NCache más escalable que una base de datos relacional? Bien, NCache forma un grupo de servidores de caché y agrupa la CPU, la memoria y otros recursos de todos estos servidores.

Y, NCache le permite agregar servidores de caché en tiempo de ejecución sin detener el caché o la aplicación. Y esto le permite escalar linealmente su aplicación y manejar cargas de transacciones extremas. Esto es algo que no puede hacer con su base de datos relacional.

Caché distribuida en memoria como NCache escala linealmente al permitirle agregar servidores de caché al clúster de caché (el nivel de almacenamiento en caché) en tiempo de ejecución. Pero, ¿qué tipo de números de rendimiento debe esperar de una solución como NCache.

A continuación se NCache números de rendimiento. Puedes ver completo NCache punto de referencia de rendimiento haga clic aquí

Números de rendimiento para NCache
Figura 3: Números de rendimiento para NCache

Como puede ver, una caché distribuida en memoria como NCache proporciona un rendimiento de submilisegundos para lecturas y escrituras y le permite escalar su capacidad de transacciones de forma lineal simplemente agregando más servidores de caché.

Ahora veamos cómo una memoria caché distribuida en memoria como NCache resuelve varios cuellos de botella de escalabilidad mencionados anteriormente.

 

Almacenamiento en caché de datos de aplicaciones

El almacenamiento en caché de datos de aplicaciones le permite eliminar los cuellos de botella de su base de datos. Caché distribuida en memoria como NCache le permite almacenar en caché los datos de la aplicación y reducir esos costosos viajes a la base de datos. Puede esperar desviar del 70 al 90 % del tráfico de la base de datos a la caché distribuida en memoria. Esto reduce la presión sobre su base de datos y le permite funcionar más rápido y manejar cargas de transacciones más grandes sin ralentizarse.

Customer Load(string customerId)
{
 // Key format: Customer:PK:1000
 string key = "Customers:CustomerID:" + customerId;
 Customer cust = (Customer) _cache[key];
 if (cust == null)
 { // Item not in cache so load from db
LoadCustomerFromDb(cust);
// Add item to cache for future reference
_cache.Insert(key, cust);
 }
 return cust;
}

Figura 4: uso de caché distribuida en memoria para el almacenamiento en caché de datos de aplicaciones

El almacenamiento en caché de datos de la aplicación significa que almacena en caché cualquier dato de la aplicación que obtenga de su base de datos relacional. Esto suele ser en forma de objetos de dominio (también llamados entidades). Aquí hay un ejemplo de cómo usar un caché distribuido como NCache para el almacenamiento en caché de datos de la aplicación.

 

Caché de estado de sesión de ASP.NET

Caché distribuida en memoria como NCache también es un gran lugar para almacenar su estado de sesión ASP.NET. Es mucho más rápido y más escalable que las tres opciones mencionadas anteriormente (InProc, StateServer y SqlServer). NCache es más rápido porque está en la memoria y proporciona una interfaz clave-valor con el valor como un "objeto" que es un estado de sesión de ASP.NET. Y es escalable porque es un caché distribuido.

Y, NCache también replica sesiones de forma inteligente a través de sus ricas topologías de almacenamiento en caché, por lo que incluso si un servidor de caché deja de funcionar, no hay pérdida de datos de la sesión. Esta replicación es necesaria porque NCache proporciona un almacenamiento en memoria y la memoria viola el almacenamiento.

NCache también acelera la serialización del objeto de estado de sesión de ASP.NET que se requiere antes de que pueda almacenarse fuera del proceso. NCache hace esto mediante el uso de su función de serialización compacta dinámica que es 10 veces más rápida que la serialización .NET normal. Puede utilizar esta función sin realizar ningún cambio en el código.

puedes enchufar NCache Proveedor de estado de sesión (SSP) a su aplicación ASP.NET haciendo algunos cambios en su archivo web.config como se muestra a continuación.

<system.web>
 ...
 <assemblies>
<add assembly="Alachisoft.NCache.SessionStoreProvider, Version=4.3.0.0,
 Culture=neutral, PublicKeyToken=CFF5926ED6A53769" />
 </assemblies>
 <sessionState cookieless="false" regenerateExpiredSessionId="true"
 mode="Custom" customProvider="NCacheSessionProvider"
timeout="20">
<providers>
 <add name="NCacheSessionProvider"
 type="Alachisoft.NCache.Web.SessionState.NSessionStoreProvider"
 useInProc="false" cacheName="myDistributedCache"
 enableLogs="false“ writeExceptionsToEventLog="false” />
</providers>
 </sessionState>
 ...
</system.web>

Figura 5: Complemento NCache como proveedor de estado de sesión (SSP) de ASP.NET en Web.Config

 

ASP.NET View State Almacenamiento en caché

Ya he descrito cómo ASP.NET View State es una cadena codificada enviada por el servidor web al navegador del usuario que luego la devuelve al servidor web en caso de una devolución de HTTP. Pero, con la ayuda de un caché distribuido de InMemory como NCache, puedes guardar esto en caché ASP.NET View State en el servidor y solo envíe una pequeña identificación única en su lugar.

NCache ha implementado un ASP.NET View State módulo de almacenamiento en caché a través de un adaptador de página ASP.NET personalizado y ASP.NET PageStatePersister. De esta manera, NCache intercepta tanto la solicitud como la respuesta HTTP. En el momento de la respuesta, NCache elimina la porción de "valor" de la cadena codificada y la almacena en caché y, en su lugar, coloca un identificador único (una clave de caché) en este "valor".

Luego, cuando llega la próxima solicitud HTTP, la intercepta nuevamente y reemplaza el identificador único con la cadena codificada real que ha colocado en el caché anteriormente. De esta forma, la página ASP.NET no nota nada diferente y usa la cadena codificada que contiene el estado de vista como lo hacía antes.

El siguiente ejemplo muestra un ASP.NET View State cadena codificada sin almacenamiento en caché y también lo que sucede cuando se incorpora el almacenamiento en caché.

//ASP.NET View State without Caching
<input id="__VIEWSTATE"
 	type="hidden"
 	name="__VIEWSTATE"
 	value="/wEPDwUJNzg0MDMxMDA1D2QWAmYPZBYCZg9kFgQCAQ9kFgICBQ9kFgJmD2QWAgIBD
		xYCHhNQcm2aW91c0NvbnRyb2xNb2RlCymIAU1pY3Jvc29mdC5TaGFyZVBvaW50Lld
		lYkNvbnRyb2xzLlNQQ29udHJbE1vZDA1XzRlMjJfODM3Y19kOWQ1ZTc2YmY1M2IPD
		xYCHhNQcm2aW91c0NvbnRyb2xNb2RlCymIAU1pY3Jvc29mdC5TaGFyZVBvaW50Lld
		lYkNvbnRyb2xzLlNQQ29udHJbE1vZDA1XzRlMjJfODM3Y19kOWQ1ZTc2YmY1M2IPD
		... ==" />
			
//ASP.NET View State with Caching
<input id="__VIEWSTATE"
	type="hidden"
	name="__VIEWSTATE"
	value="vs:cf8c8d3927ad4c1a84da7f891bb89185" />

Figura 6: ASP.NET View State Cadena codificada con o sin almacenamiento en caché

 

Caché de salida ASP.NET para salida de página estática

ASP.NET proporciona un marco de caché de resultados de ASP.NET para abordar el problema de la ejecución excesiva de páginas incluso cuando el resultado de la página no cambia. Este marco le permite almacenar en caché la salida de la página completa o de algunas partes de la página, de modo que la próxima vez que se llame a esta página, no se ejecutará y, en su lugar, se mostrará su salida en caché. Mostrar una salida ya almacenada en caché es mucho más rápido que ejecutar toda la página nuevamente.

<caching>
   <outputCache defaultProvider ="NOutputCacheProvider">
     <providers>
       <add name="NOutputCacheProvider"
         type="Alachisoft.NCache.OutputCacheProvider.NOutputCacheProvider,
               Alachisoft.NCache.OutputCacheProvider, Version=x.x.x.x,
               Culture=neutral, PublicKeyToken=1448e8d1123e9096"
				  
               cacheName="myDistributedCache" exceptionsEnabled="false"
               writeExceptionsToEventLog="false" enableLogs="true” />"
     </providers>
   </outputCache>
</caching>

Figura 7: Configuración del proveedor de caché de salida de ASP.NET para NCache en Web.Config

NCache ha implementado un proveedor de caché de salida ASP.NET para .NET 4.0 o versiones posteriores. Esto le permite conectarse NCache sin problemas y sin ningún esfuerzo de programación. En caso de NCache, este proveedor es para una caché distribuida en memoria que abarca varios servidores. Por lo tanto, si su aplicación ASP.NET se ejecuta en una granja web con equilibrio de carga, la salida de la página almacenada en caché desde el servidor 1 está disponible de inmediato para todos los demás servidores de la granja web. A continuación se muestra cómo puede conectarse NCache como proveedor de caché de resultados de ASP.NET.

 

Arquitectura de caché distribuida

Las aplicaciones ASP.NET de alto tráfico no pueden darse el lujo de dejar de funcionar, especialmente durante las horas pico. Para este tipo de aplicaciones, existen tres objetivos arquitectónicos importantes que una buena caché distribuida en memoria como NCache proporciona. Ellos son:

  1. Alta disponibilidad
  2. escalabilidad lineal
  3. Replicación de datos y confiabilidad

Permítanme explicar cada área a continuación.

 

Alta disponibilidad

Uno de los objetivos arquitectónicos más importantes de NCache es lograr alta disponibilidad y elasticidad de caché. Y lo hace a través de las siguientes capacidades arquitectónicas:

  1. Clúster de caché peer-to-peer de recuperación automática: NCache construye un grupo de servidores de caché sobre TCP/IP. Este clúster tiene un peer-to-peer arquitectura que significa que no hay nodos maestro/esclavo y no hay clústeres de regla mayoritaria. En cambio, cada nodo es un par igual. Esto permite NCache para manejar situaciones en las que cualquier nodo podría fallar y el clúster se ajusta automáticamente y continúa ejecutándose, y no hay interrupción para su aplicación.
  2. Configuración dinámica: Esto significa que no tiene que codificar las cosas en los archivos de configuración. Esto es porque NCache propaga una gran cantidad de información de configuración a los clientes de caché (es decir, sus aplicaciones) en tiempo de ejecución. Entonces, cuando agrega un servidor de caché en tiempo de ejecución, la membresía del clúster se actualiza automáticamente y el clúster informa a todos los clientes de caché sobre este cambio. Hay una gran cantidad de otros cambios de configuración que se manejan de la misma manera.
  3. Soporte de conmutación por error de conexión: Esta es una capacidad en la que cuando un servidor de caché deja de funcionar, el clúster de caché y los clientes de caché pueden continuar trabajando sin ninguna interrupción. En el caso del clúster de caché, ya he discutido su calidad de autorreparación que aborda esta situación. En el caso de los clientes de caché, esto significa que el cliente de caché continúa trabajando interactuando con otros servidores de caché en el clúster.
 

Replicación de datos con escalabilidad lineal

Desde caché distribuida en memoria como NCache utiliza la memoria como almacén, debe proporcionar replicación de datos para garantizar la confiabilidad. Pero, al mismo tiempo, no puede comprometer la escalabilidad lineal porque esa es la razón más importante para usar un caché distribuido como NCache.

Éstos son algunos NCache Topologías de almacenamiento en caché que ayuden a lograr ambos objetivos.

  1. Caché con particiones: NCache divide la memoria caché en función del número de servidores de memoria caché y asigna una partición a cada servidor de memoria caché. También ajusta la cantidad de particiones cuando agrega o elimina servidores de caché en tiempo de ejecución. El particionamiento es la forma principal de garantizar la escalabilidad lineal porque, a medida que agrega más servidores, esta topología de almacenamiento en caché aumenta el tamaño de almacenamiento general y también la potencia de procesamiento de la CPU.
  2. Caché de réplica particionada: Además de dividir, NCache también proporciona réplicas para cada partición. Estas réplicas residen en servidores de caché diferentes a los de la propia partición para garantizar que, si un servidor de caché deja de funcionar junto con su partición, la réplica estará disponible de inmediato. De esta manera, se proporciona confiabilidad en los datos. Al replicar cada partición solo una vez en otro servidor de caché, NCache logra la confiabilidad de los datos sin comprometer la escalabilidad lineal.
  3. Caché del cliente (caché cercano): Otra capacidad muy importante de NCache es caché de cliente. Este es un caché local que se encuentra en la máquina del cliente de caché (es decir, su servidor web o de aplicaciones) e incluso puede ser InProc (lo que significa que reside dentro de su proceso de aplicación). Esto es esencialmente un caché encima de un caché y proporciona ganancias de rendimiento extremas junto con una mayor escalabilidad de NCache sí mismo porque el tráfico incluso al nivel de almacenamiento en caché cae.
Topología de almacenamiento en caché de réplicas de partición de NCache
Figura 8: Topología de almacenamiento en caché de réplica de partición de NCache

Como puede ver, Partitioned-Replica Cache coloca una partición y una réplica en cada servidor de caché. Y garantiza que la réplica siempre esté en un servidor de caché diferente por motivos de confiabilidad.

 

Conclusión

He tratado de resaltar los cuellos de botella de rendimiento y escalabilidad más comunes que enfrentan las aplicaciones ASP.NET hoy en día y mostrarle cómo superarlos mediante el uso de una memoria caché distribuida en memoria como NCache. NCache es un caché distribuido de código abierto para aplicaciones .NET y Java. Por lo tanto, puede usarlo sin restricciones. Puede obtener más información sobre NCache en el siguiente enlace

¿Qué hacer a continuación?

© Copyright Alachisoft 2002 - Todos los derechos reservados. NCache es una marca registrada de Diyatech Corp.