Colabora |
WebService AsíncronoDesarrollo de métodos asíncronos en el lado servidor
Fecha: 27/Nov/2007 (23/11/2007)
|
IntroducciónDurante estas semanas pasadas me he encontrado con el problema de diseñar un sistema escalable que funcione con una interfaz WebService. Aparentemente todo es sencillo si no fuera porque las tareas a realizar en el WS son en algunos casos pesadas y se puede dilatar algunos segundos en el tiempo. Esto provoca que la escalabilidad del sistema se vea comprometida. Tras estudiar el problema uno llega a la conclusión de que una posible solución es ejecutar las tareas de forma asíncrona. Hablamos de ejecución asíncrona de un WS en el lado servidor. Por otro lado, seguro que todos aquellos
programadores que habitualmente trabajéis con WebServices
. Estaréis familiarizados con las clases proxy que genera
el propio Visual Studio. Si os fijáis un poco en la clase
proxy que os genera veréis como os ha generado para cada
WebMethod dos formas diferentes de llamarlo, una de forma síncrona
y otra de forma asíncrona. De este modo se soluciona el que
la aplicación cliente quede bloqueada a la espera de que
un WS termine. Pero no hay nada sobre cómo se ejecuta en
el lado servidor. Reproducir el problema. Generamos un WS con el siguiente WebMethod [WebMethod] public int SumaSincrono(int a, int b) { System.Threading.Thread.Sleep(3000); return a + b ; } ¡¡¡¡Simple!!! Si lo ejecutamos…. A los 3 segundos
obtenemos una respuesta con el resultado de la suma. El problema
esta cuando simulamos 200 usuarios simultáneos. ¡¡Sorpresa!!
Fundamento TeóricoCuando nosotros ejecutamos una página ASP.NET esta se ejecuta consumiendo un thread del Pool reservado a ASP.NET. Hay que saber que aunque el CLR reserva 100 thread por CPU para ASP.NET, este únicamente hace uso de 12 thread por CPU. En el ejemplo cada llamada tiene "ocupado"
un thread durante 3 segundos, por lo que se hace muy complicado
soportar 200 usuarios simultáneos. ¡Por cierto! Mi
maquina tiene un CoreDuo por lo que tenemos 24 Thread disponibles. La soluciónExisten un montón de documentación referentes a las diferentes técnicas de realizar paginas aspx asíncronas, pero apenas se encuentra documentación referente a como realizar un webservice asíncrono en el lado servidor. http://msdn2.microsoft.com/en-US/library/aa480516.aspx Escribimos el siguiente código. public delegate int SumaAsincronoDelegado (int a, int b); public class MyState { public object EstadoPrevio; public SumaAsincronoDelegado dlg; } [WebMethod()] public IAsyncResult BeginSumaAsincrono(int a, int b, AsyncCallback cb, object s) { SumaAsincronoDelegado dlg = new SumaAsincronoDelegado(SumaAsincrono); MyState ms = new MyState(); ms.dlg = dlg; ms.EstadoPrevio = s; return dlg.BeginInvoke(a, b, cb, ms); } [WebMethod] public int EndSumaAsincrono(IAsyncResult call) { MyState ms = (MyState)call.AsyncState; return ms.dlg.EndInvoke(call); } private int SumaAsincrono(int a, int b) { System.Threading.Thread.Sleep(3000); return a + b; } Ahora el método "SumaAsincrono"
se ha desdoblado en "BeginSumaAsincrono" y "EndSumaAsincrono"
De forma genérica podemos decir que todo método lo
podemos hacer asíncrono simplemente añadiéndole
los prefijos Beginxxx y Endxxx. Y que cumplan con las firmas : [WebMethod] public IAsyncResult Beginxxx([parametros de entrada], AsyncCallback cb, object s) [WebMethod] public [Tipo] Endxxx(IAsyncResult call) ¿Cómo se ve el método desde un cliente? Pues igual que si lo hiciéramos de forma síncrona, es decir aparece un método "xxx" Para el cliente es trasparente el si ejecutamos el método de forma síncrona o asíncrona en el lado servidor. ¡¡Ahora llega la hora de la verdad!! Para dar fe de lo que os estoy contando, he realizado un test para verificar la mejora en la escalabilidad. Tras estabilizarse el servidor cada petición tiene una duración de unos 3,2 segundos. Apenas una par de decimas de retraso y soportando 200 usuarios. ¿Qué ha ocurrido?Ahora cada petición se ejecuta en un thread distinto unos de esos 88 thread por cpu que no utiliza asp.net, dejando los 12 thread/cpu libres para admitir nuevas peticiones. Con este artículo he tratado de ilustrar como realizar WebServices escalables Un saludo. José Luis Martín. |
Código de ejemplo (comprimido): |
Fichero con el código de ejemplo: phydelta_ws_asincrono_codigo.zip
- 18.8 KB
|