Un cliente, como siempre, me ha preguntado cómo puede medir el desempeño de los Web Services que piensa Construir utilizando DotNet.
Le escribí el siguiente mail, para que pueda usarlo como una guía para hacer mediciones.
¿Cómo funcionan los Web Services?
La arquitectura de los Web Services [1] está basada en la infraestructura ASP.NET y usa serialización XML [2]. Cuando un el servidor Web procesa una requerimiento HTTP para un Web Services, Internet Information Server (IIS) [3] mapea la extensión (.asmx) a la interfaz de programación de aplicaciones Internet Server (ISAPI) [4] de ASP.NET (Aspnet_Isapi.dll). Está ISAPI entonces envía el requerimiento al proceso de trabajo de ASP.NET, donde entra en el Pipeline de procesamiento de requerimientos, el cual es contralo por el objeto HttpRuntime [5]. Esto se muestra en el diagrama 1.
Diagrama 1: Arquitectura ASP.NET Web Services y flujo de requerimientos
El requerimiento pasa inicialmente por el objeto HttpApplication [6], seguido por la serie de objetos HttpModule [7] registrados. Los objetos HttpModule son registrados en el archivo de configuración Machine.config o en la sección <httpModules> del Web.config de cada Servicio Web. Los objetos HttpModule son los responsables de manejar los aspectos como autentificación, autorización, Caching y otras tareas trasversales.
Luego de pasar el requerimiento a través de los módulos HTTP en el Pipeline, el objeto HttpRuntime verifica con el administrador Webservicehandlerfactory [8] que la extensión .asmx esté registrada. Este crea una instancia del administrador HTTP que es responsable de procesar el requerimiento al Web Services. Este administrador (Handle) deriva de WebServicesHandler [9]. El administrador HTTP usa reflexión (Reflection) [10] para trasformar el mensaje SOAP en invocaciones a los métodos del Web Services.
Medidas de desempeño para Web Services
Para determinar de manera efectiva el desempeño de Web Services en DotNet es necesario poder medir los siguientes aspectos:
-
Throghput: Medida de la cantidad de requerimientos ejecutados por segundo y cuellos de botella relativos al Throghput, como el número de requerimiento en espera de ser ejecutados y el número de requerimientos que se están rechazando.
- Cost of throghput: Medida del uso de procesador, memoria, I/O de disco y utilización de red para responder a los requerimientos que se están ejecutando.
- Request Execution Time: medida del tiempo que toma la ejecución de un método del Web Services en el servidor.
- Latency: Medida del tiempo que toma la ejecución y llegada de la respuesta al cliente de un requerimiento al Web Services.
- Cache utilization: Medida de la razón entre Cache Hits y Cache misses. Esto necesita ser visto en un contexto amplio porque el uso de memoria virtual afecta el desempeño del cache.
- Error and Exception: medida del número de errores y excepciones generadas.
- Xml Serialization: Mide el costo de la serialización de XML, muy importante en los Servicios Web.
¿Cómo medir?
Como los Web Services son un caso particular de ASP.NET es necesario aclarar primero como medir desempeño en ASP.NET. Para esto es necesario preliminarmente utilizar la herramienta Performance Counter [12].
El siguiente diagrama 2 muestra el ciclo de vida de los requerimientos en ASP.NET.
Diagrama 2: Ciclo de vida y medidas para un requerimiento ASP.NET
Throughput
-
ASP.NET Applications\Requests/Sec
Umbral: depende de la lógica de negocio.
Significado: es uno de los primeros indicadores que se usan para calcular la capacidad necesaria para el sistema.
-
Web Service\ISAPI Extension Requests/sec
Umbral: depende de la lógica de negocio.
Significado: La tasa de requerimientos a la ISAPI que se están procesando simultáneamente. Este contador no es afectado por los Work process que se reinician como si lo es ASP.NET Applications\Requests/Sec.
Cost of Throughput
El costo del throughput es la medida del uso de procesador, memoria, I/O de disco y utilización de red para responder a los requerimientos que se están ejecutando. Esto no es específico a los Web Servies ni ASP.NET. Pueden verse los indicadores en detalle en el capítulo 15, sección System Resource [11].
Request
-
ASP.NET\Requests Current
Umbral: No tiene un valor específico.
Significado: Número de requerimientos que está manejando la ISAPI, incluidos encola, ejecutándose y esperando a escribir en el cliente. ASP.NET comienza a rechazar requerimientos cuando el contador excede el número definido en requestQueueLimit.
-
ASP.NET Applications\Requests Executing
Umbral: No tiene un valor específico.
Significado: Número de requerimientos que se están ejecutando. El objeto HttpRuntime controla este contador, incrementándolo cuando atiende un nuevo requerimiento y disminuyéndolo cuando terminar de procesar el requerimiento.
-
ASP.NET Applications\ Requests Timed Out
Umbral: No tiene un valor específico.
Significado: Cantidad de requerimientos que dieron TimeOut y no se ejecutaron.
Queues
-
ASP.NET\ Requests Queued
Umbral: No tiene un valor específico.
Significado: Cantidad de requerimientos actualmente en colas. Los requerimientos encolados tienen un límite fijado por configuración en el parámetro requestQueueLimit que tiene como límite por defecto 5.000.
-
ASP.NET Applications\ Requests In Application
Umbral: No tiene un valor específico.
Significado: Cantidad de requerimientos actualmente en cola para cada directorio virtual, que es el equivalente a una aplicación. Estos requerimientos encolados tienen un límite fijado por configuración en el parámetro appRequestQueueLimit , cuando es superado este límite retorna el mensaje "Server Too busy".
-
Queue ASP.NET\ Requests Rejected
Umbral: No tiene un valor específico.
Significado: representa el número de requerimientos rechazados porque la cola de requerimientos está llena. ASP.NET Work Process comienza a rechazar requerimientos cuando sobrepasa el límite configurado en requestQueueLimit la medida ASP.NET\ Requests Queued.
-
ASP.NET\ Requests Wait Time
Umbral: 1.000 milisegundos, El promedio debe tender a cero segundos de tiempo de espera en la cola de requerimientos.
Significado: representa el tiempo de espera del último requerimiento en la cola Name Pipe entre IIS y el Work Process ASP.NET. Esta medida no incluye ningún otro tiempo de espera.
Response Time and Latency
El tiempo de respuesta y la latencia pueden ser medidos desde la perspectiva del cliente o del servidor. Del lado del cliente, se puede medir el tiempo desde que llega el primer y el último byte de la respuesta. La latencia en este caso incluye la latencia de la red (tiempo que agrega la red) y la latencia del servidor (tiempo que toma el servicio en responder al requerimiento). La medida del primer Byte se llama TTFB y la del último TTLB y se pueden capturar con herramientas como ACT [13].
En el lado del cliente es posible medir el tiempo de ejecución de un requerimiento utilizando el contador ASP.NET\Request Execution Time. El diagrama 3 muestra las principales componentes necesarias para estas medidas.
Diagrama 3
-
TTFB
Umbral: Depende del tipo de requerimiento.
Significado: Tiempo que pasa entre el envío del requerimiento y la recepción del primer Byte de la respuesta.
-
TTLB
Umbral: Depende del tipo de requerimiento.
Significado: Tiempo que pasa entre el envío del requerimiento y la recepción del último Byte de la respuesta.
-
ASP.NET\Request Execution Time
Umbral: Depende del tipo de requerimiento.
Significado: Tiempo que se tomó la ejecución del último requerimiento procesado.
Cache Utilization
-
ASP.NET Applications\Cache Total Entries
Umbral: no tiene un valor específico.
Significado: este contador muestra la cantidad de elementos en el cache, tanto internos como externos. ASP.NET usa el chache para almacenar objetos que son caros de crear por ejemplo objetos de configuración.
-
ASP.NET Applications\Cache Total Hit Ratio
Umbral: Con memoria suficiente normalmente se debe tener sobre el 80%.
Significado: este contador muestra las llamadas al Cache tanto internas como externas.
Loading
-
.NET CLR Loading\ Current appdomains
Umbral: el valor debe ser el mismo que el numero de aplicaciones Web más uno.
Significado: el número de Appdomains cargados en el proceso.
-
.NET CLR Loading\ Current Assemblies
Umbral: No tiene un valor específico.
Significado: el número de Assemblies cargados en el proceso.
Worker Process Restarts
-
ASP.NET\ Worker Process Restarts
Umbral: No tiene un valor específico.
Significado: el número de veces que se recicla al aplicación Web y el Work process.
Xml Serialization
Cuando se serializa y se hidrata un objeto, proceso inverso, es posible calcular el costo de estas acciones en términos del uso de memoria y el tamaño de la data. Para esto se puede utilizar el siguiente código de ejemplo [11].
using System;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using System.Text;
using System.Data;
//A sample class for serialization
public class MyClass
{
public string name;
public string surName;
public MyClass()
{
name = "FirstName";
surName = "LastName";
}
}
class Class1
{
private static long startMemory, endMemory, gcMemory, actualMemory,
overHeadMemory;
private static double percentOverhead;
static void Main(string[] args)
{
//stream to which the class object shall be serialized
Stream fs = new FileStream("SomeFile.txt", FileMode.Create);
MyClass mc = new MyClass(); XmlSerializer xs = new XmlSerializer(typeof(MyClass));
XmlWriter writer = new XmlTextWriter(fs, new UTF8Encoding());
// Clean up the GC memory and measure the measuring as the baseline before
// performing the serialization
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
startMemory = System.GC.GetTotalMemory(false);
xs.Serialize(writer, mc);
//Calculate the overhead and the amount of data after serialization
CalculateOverhead(fs.Position);
DisplayInfo();
writer.Close();
fs.Close();
Console.ReadLine();
}
public static void CalculateOverhead(long streamPosition)
{
endMemory = System.GC.GetTotalMemory(false);
gcMemory = endMemory – startMemory;
actualMemory = streamPosition;
overHeadMemory = gcMemory – actualMemory;
percentOverhead = ((double)(overHeadMemory * 100)) /
(double)actualMemory;
}
public static void DisplayInfo()
{
Console.WriteLine("Total amount of data after serialization ->" + actualMemory);
Console.WriteLine("Total memory used by GC for serialization ->" + gcMemory);
Console.WriteLine("Overhead memory used serialization ->" + overHeadMemory);
Console.WriteLine("Percent overhead ->" + percentOverhead);
}
}
Código 1: Serialización
Referencias
- Web Serices, http://en.wikipedia.org/wiki/Web_services
- Serialización XML, http://msdn2.microsoft.com/es-es/library/90c86ass(VS.80).aspx
- Internet Information Services, http://es.wikipedia.org/wiki/IIS
- ISAPI, http://en.wikipedia.org/wiki/ISAPI
-
HttpRuntime (Clase) ,
http://msdn2.microsoft.com/es-es/library/system.web.httpruntime(VS.80).aspx
-
HttpApplication ,
http://msdn2.microsoft.com/es-es/library/system.web.httpapplication(VS.80).aspx
- HttpModules, http://msdn2.microsoft.com/en-us/library/zec9k340(VS.71).aspx
-
WebServiceHandlerFactory Class,
http://msdn2.microsoft.com/en-us/library/system.web.services.protocols.webservicehandlerfactory.aspx
-
Securely Implement Request Processing, Filtering, and Content Redirection with HTTP Pipelines in ASP.NET,
http://msdn.microsoft.com/library/default.asp?url=/msdnmag/issues/02/09/httppipelines/
- Reflection (computer science), http://en.wikipedia.org/wiki/Reflection_(computer_science)
-
Improving .NET Application Performance and Scalability,
-
Working with Performance Counters,
http://www.microsoft.com/technet/prodtechnol/acs/reskit/acrkch10.mspx
-
Microsoft Application Center Test,
http://msdn2.microsoft.com/en-us/library/aa287410(VS.71).aspx