Archivo de la categoría: Q&A

Aplicación Windows Mobile con BackOffice SAP ¿Cómo sincronizar Datos?

Hola,

Me llegó la siguiente pregunta, muy interesante por eso la subo aquí a la sección de Q&A del Blog.

Problemática

Una empresa quiere desarrollar una aplicación móvil en Windows Mobile que funcione desconectada con datos extraídos de SAP en la mañana (usando la cuna) y por la tarde poniéndolos en el móvil en la cuna subir los datos nuevamente. Para ello utiliza un Web Service que expone el módulo Business Connector.

¿Cómo hacer eso? ¿Usar Active Sync?

“Solucionatica”

En este caso se me ocurren dos soluciones, la primera 100% implementada en Service-Oriented y la segunda una combinación de Data-Centric y Service-Oriented. Para los que no estén familiarizados con estos conceptos, pueden ver este POST.

 

Opción 1: Service-Oriented

Que la aplicación móvil consuma los servicios Web de descarga de datos directamente (cuando está en la cuna) e inserte los valores en la DB. Luego la aplicación trabaja desconectada para al final del día cuando sea puesta en la cuna subir los datos a través de un Servicio Web de Update y solución de conflictos.

 

Opción 2: Mixta Service-Oriented y Data-Centric

En esta solución se utilizaría una base de datos intermedia (MSSQL2005) la cual utilizando SSIS cargaría los datos desde SAP a través del Web Services. Luego, utilizando replicación con la PDA transfiere los datos necesarios para móvil. Luego al final del día se sincronizan los datos utilizando las facilidades de MSSQL y su motor de resolución de conflictos. Por último, SSIS pasa los datos ya consolidados desde MSSQL a SAP a través del Web Services de Upload.

Los Pro y contras de cada solución.

 

Aspecto

Service-Oriented

Mixta

Esfuerzo de programación.

Alto, la resolución de conflictos no es simple

Si MSSQL resuelve los conflictos es trivial.

Costos Licenciamiento

Sin costos adicionales.

Licencia de MSSQL 2005

Rapidez de descarga

Está es más rápida, no tiene SSIS intermediando ni el servicio de replicación de MSSQL.

Tiene una pieza intermedia extra.

Efectividad en resolución de conflictos en datos

Puede ser 100% efectiva, todo depende de la lógica programada.

Tiene las limitaciones del motor de resolución de conflictos de MSSQL, que no es malo pero tiene sus limitaciones.

Administración

Solo se requiere instalar la aplicación.

Además de instalar la aplicación hay que configurar en cada equipo la replicación.

Conocimientos del equipo

Web Services.

Aplicaciones Móviles.

TSQL

Web Services

Aplicaciones móviles

SSIS y TSQL

En mi opinión yo tomaría la opción 1 si tengo un equipo de desarrollo con experiencia. Si no es así me iría por la opción mixta, para no tener que programar la resolución de conflictos.

Salu2

BlackBerry ¿Cómo Cargar un JAR sin usar un Servidor BES?

Un estudiante que está comenzando a desarrollar en BlackBerry me pregunta cómo puede cargar un programa cliente Java, JAR/JAD por ejemplo, a su teléfono BlackBerry.

El proceso regular para cargar aplicaciones en el teléfono Blackberry es a través de un Servidor BES (BlackBerry Enterprise Server).

Ahora, describo los detalles de cómo convertir los ficheros JAR/JAD en ficheros ALX/COD, para poder cargar manualmente las aplicaciones en los terminales BlackBerry, por ejemplo, a través del Desktop Manager.

INSTRUCCIONES:

Se requiere que descargues 2 programas y que los instales en el PC/Laptop donde se realizará la conversión de los ficheros. Los programas que se requiere instalar son:

Sun Java SDK:

Lo puedes descargar de la web: http://java.sun.com/j2se/1.4.2/download.html

*** Asegurate que descargues el SDK y no el JRE

RIM Java Development Environment (JDE):

Lo puedes descargar de la web: http://www.blackberry.net/developers/

Yo personalmente tengo instalado múltiples versiones del JDE, pero la conversión de estos ficheros la hice con el 4.0.2

Una vez que ambos programas estén instalados, puedes copiar los ficheros a convertir (los midlets) .JAR y .JAD.

Para facilidad de uso, se pueden copiar los ficheros mencionados antes, al directorio BIN del Java Development Environment, por ejemplo:

c:\program files\Research in Motion\Blackberry JDE 4.0.2\bin\

Para la conversión de los ficheros se utiliza la herramienta RAPC.exe (este ejecutable se encuentra en el subdirectorio BIN de la instalación del programa JDE), a través de la línea de comandos DOS. He resumido el procedimiento y básicamente la línea que debes utilizar en la ventana de DOS para realizar la conversión de los ficheros JAD y JAR en COD y ALX es:

rapc import="C:\Program Files\Research In Motion\BlackBerry JDE 4.0.2\lib\net_rim_api.jar" codename=Sametime75 -midlet jad=Sametime75.jad Sametime75.jar

Donde debes reemplazar el nombre asociado a la variable "codename" y los nombres indicados en la entrada "-midlet jad", que en el ejemplo he llamado Sametime75, por el nombre de la aplicación y el nombre de los ficheros a utilizar.

Recuerda:

– Los ficheros los tienes que copiar en el directorio BIN del JDE 4.0.2 (el JAR y el JAD)

– El programa RAPC lo debes ejecutar desde la carpeta BIN también

Una vez que ejecutas el comando RAPC, se genera el fichero .COD en la carpeta BIN. Para generar el ALX, sólo necesitas el NotePad de Windows y editar la siguiente plantilla que te anexo:

<loader version="1.0">
    <application id="SAMETIME">
        <name>SAMETIME</name>
        <description>Version 7.5</description>
        <version>7.5</version>
        <vendor>Vendor Name</vendor>
        <copyright>Not needed but can be anything</copyright>
        <fileset Java="1.0">
            <files>
                Sametime75.cod
            </files>
        </fileset>
    </application>
</loader>

Nuevamente reemplaza los nombres donde he incluido "Sametime", con el nombre de tu aplicación, y reemplaza las entradas como "description", "version" y "copyright", con la información que quieras agregar. Luego "salva este fichero como tipo ALX", NO como texto (TXT).

Con esto ya tendrás el fichero .COD y el fichero .ALX.

Saludos,

Windows Comunication Foundation WCF, ¿Como habilitar un cache?

Problemática

En un proyecto se está construyendo un ESB que tiene un despachador. Este despachador recibe las llamadas de las aplicaciones clientes y viendo en el catálogo de servicio resuelve que por cuales "filtros" hace pasar la llamada antes de invocar el servicio de Negocio que implementa la lógica que el cliente espera.

La idea es que el despachador arma un "Pipe" para cada servicio en el cual incluye los filtros que en el catálogo de servicios fueron configurados para ese servicio. Por ejemplo, un servicio puede tener los filtros de LOG y Medición de tiempos, mientras que otro servicio puede tener configurado LOG y Caché.

Para aumentar el desempeño hay que evitar que por cada llama a un servicio el despachador vaya a la base de datos del catálogo de servicios para armar el Pipe, si ya lo llamó no necesita ir a leer nuevamente cuales son los filtros que el pipe de ese Servicio contiene.

Aquí viene la pregunta ¿Cómo hago en WCF para poder mantener en memoria los Pipe de servicios que fueron llamados? Con la idea de evitar volver a leer la configuración.

 

"Solucionatica"

Bueno, está preocupación por la optimización de los tiempos de respuesta en el despachador es muy buena porque usando el concepto de Cache se pueden evitar consultas a la base de datos, reemplazándolas por consultas en memoria, lo que haría mucho más rápido el tiempo de respuesta.

WCF brinda opciones para poder implementar esto. Yo escogí incluir el Cache en el Host como propiedades. La clase Host es la que levanta los EndPoint en WCF y aloja los servicios. Todas las instancias de servicios que se ejecutan tienen acceso al Host, por lo que instalar ahí el cache se hace simple. Ahora, ojo con la concurrencia ya que las ejecuciones de las llamadas al servicio son concurrentes.

A.- Primero veamos la clase Pipe (Qué simula el Pipe del problema).

La clase Pipe es el recurso que queremos poder poner el en Cache de nuestro Servicio. Se muestra en el código uno la clase.

El código 1 muestra el elemento Pipe que será el recurso a almacenar en el Cache.

/// <summary>

/// Pipe de ejemplo, elemto a poner el en cache

/// </summary>

public class Pipe

{

private int _idServicio;

 

public int idServicio

{

get { return _idServicio; }

set { _idServicio = value; }

}

private DateTime fechaCreacion;

 

public DateTime FechaCreacion

{

get { return fechaCreacion; }

set { fechaCreacion = value; }

}

 

public Pipe(int IdServicio)

{

this._idServicio = IdServicio;

}

}

Código 1: Clase Pipe, elemento a poner cache

B.- Clase HostPuls.

Está clase extiende la clase ServiceHost de WCF para agregarlo propiedades que manejarán el Cache que estamos implementando.

La propiedad privada _CachePipe es una Lista de elementos del tipo Pipe. Es aquí donde se almacenarán los elementos Pipe que ya se conocen.

El método AddPipeCache agrega un elemento Pipe nuevo al Cache.

El método public Pipe BuscarPipe recibe el identificar del servicio y retorna el Pipe que le corresponde.

El código 2 muestra la clase HostPlus que es el Host extendido.

/// <summary>

/// Host de WCF especializado para mantener en Cache elementos

/// PIPE. Hereda de ServiceHost.

/// </summary>

public class HostPlus : ServiceHost

{

private int iIdServicioBusquedaCache = 0;

private int lala = 0;

public int Lala

{

get { return lala; }

set { lala = value; }

}

/// <summary>

/// Lista de elementos Pipe en Cache.

/// </summary>

private List<Pipe> _CachePipe = new List<Pipe>();

/// <summary>

/// Agrega de manera segura un elemento al Cache de PIPE’s

/// </summary>

/// <param name="nuevoPipe"></param>

public void AddPipeCache(Pipe nuevoPipe)

{

lock (this._CachePipe)

{

this._CachePipe.Add(nuevoPipe);

}

}

/// <summary>

/// Valida si el Pipe es del servivio identificado

/// por la propiedad iIdServicioBusquedaCache;

/// </summary>

/// <param name="Pipe">Elemento del Pipe</param>

/// <returns>Verdadero o falso </returns>

private bool BuscarPipe(wcfHolaMundo.HostMaster.Pipe Pipe)

{

return Pipe.idServicio == iIdServicioBusquedaCache;

}

/// <summary>

/// Implementa la busqueda de un Pipe para el Servicio.

/// </summary>

/// <param name="idServicio">Id del servicio</param>

/// <returns>Pipe que es de ese servicio</returns>

public Pipe BuscarPipe(int idServicio)

{

iIdServicioBusquedaCache = idServicio;

return this._CachePipe.Find(new Predicate<wcfHolaMundo.HostMaster.Pipe>(this.BuscarPipe));

 

}

/// <summary>

/// Limpia el Cache, lista de Pipe.

/// </summary>

/// <returns></returns>

public bool ClearPipeCache()

{

{

lock (this._CachePipe)

{

this._CachePipe.Clear();

}

}

return true;

}

/// <summary>

/// Constructor

/// </summary>

public HostPlus()

: base()

{

 

}

/// <summary>

/// Constructor

/// </summary>

/// <param name="singletonInstance"></param>

/// <param name="baseAddress"></param>

public HostPlus(object singletonInstance, params Uri[] baseAddress)

: base(singletonInstance, baseAddress)

{ }

/// <summary>

/// Constructor

/// </summary>

/// <param name="serviceType"></param>

/// <param name="baseAddress"></param>

public HostPlus(Type serviceType, params Uri[] baseAddress)

: base(serviceType, baseAddress)

{ }

 

}

Código 2: HostPlus

C.- El método del Servicio que recibe la llamada y valida en el cache.

El método "LlamarServicio(int idServicio)" es el método del servicio que recibe un identificador del servicio con el cual se busca en el cache. Si no se encuentra lo crea y agrega al cache para las siguientes llamadas.

¿Cómo una instancia del servicio tiene acceso al cache en el Host?

El acceso al Host se hace a través del "OperationContext". Esa clase tiene el método estático Current que permite acceder al contexto de la operación. Este contexto a su vez accede al Host usando este método "operationContext.Host". Ahora se debe hacer un CAST para pasar del tipo host a nuestro Host especializado el cual tiene el Cache implementado.

Una vez que tenemos nuestro Host podemos buscar en el Cache si el Pipe de ese servicio está almacenado. Para eso usamos myHost.BuscarPipe(idServicio).

Si se encuentra el Pipe, se responde con los datos de ese Pipe. Si no se encuentra se crea usando new wcfHolaMundo.HostMaster.Pipe(idServicio) y almacenando en el cache myHost.AddPipeCache(elPipe).

El siguiente código muestra el método completo del servicio.

/// <summary>

/// Este Servicio recibe el identificador

/// de un servicio y retorna un mensaje Nevo o Viejo

/// si es que existe o no en el Cache.

/// Si no existe lo crea en el cache.

/// </summary>

/// <param name="idServicio">Identificador </param>

/// <returns>Nevo o Viejo</returns>

public string LlamarServicio(int idServicio)

{

string strREspuesta = "";

///Contexto en el que se ejecuta el Servicio

OperationContext operationContext = OperationContext.Current;

///Instancia del Host

ServiceHost host = (ServiceHost)operationContext.Host;

///instanacia del HostPlus, con Cache implementado.

wcfHolaMundo.HostMaster.HostPlus myHost =

(wcfHolaMundo.HostMaster.HostPlus)host;

wcfHolaMundo.HostMaster.Pipe elPipe;

//Busca en el cache si el Pipe existe para un servicio

elPipe = myHost.BuscarPipe(idServicio);

if (elPipe == null)

{

///No existe Pipe para este Servicio.

///Se Crea.

elPipe = new wcfHolaMundo.HostMaster.Pipe(idServicio);

elPipe.FechaCreacion = DateTime.Now;

myHost.AddPipeCache(elPipe);

strREspuesta = "Nuevo";

}

else

{

///Existe Pipe para este Servicio

strREspuesta = "Viejo, creado el " + elPipe.FechaCreacion.ToString();

}

Console.WriteLine(idServicio.ToString() + ": " + strREspuesta);

return strREspuesta ;

}

Código 3: Método del Servicio.

De esta manera se ha implementado un Cache para aumentar el desempeño evitando en lo posible el tener que crear recursos ya conocidos por el servicio.

El código del Servicio, Host y cliente para probarlo se puede descargar desde aquí.

Proxy Dinámico en WCF

Para un proyecto de ESB un ingeniero de software me pregunta cómo hacer un Proxy dinámico en WCF. Entonces yo que soy muy estudioso le digo de inmediato “usemos MEX!!!”

Este Ingeniero me dice ok necesito un ejemplo. Yo le digo, tengo uno te lo mando….. Problema no encuentro el ejemplo así que voy y le pregunto a dios Google “WCF Dynamic Proxy” y me lleva a esta librería que encapsula toda la complejidad del intercambio del metadata y lo deja en una librería bien armada.

Les sugiero que vean este ejemplo, todas las flores para el autor.

Ejemplo de Proxy Dinámico

Salu2

Biztalk Server ¿Cómo filtrar en el mapper?

Para un proyecto de BizTalk Server 2006 tuvimos que usar el Mapper de manera intensa. Una de las cosas que aprendí implementando unas transformaciones algo que suena my trivial, y en rigor lo es pero cuando uno sabe cómo hacerlo.

La problemática es la siguiente:

Si quiero pasar de un esquema A a un esquema B, dónde el mensaje original tiene un Record con múltiples filas y el destino sólo requiere una fila debemos filtrar.

 ¿Cómo puedo filtrar usando el mapper?

La solucionatica.

Para esto se deben usar dos Functoids:

 

  • Equal: Use the Equal functoid to return the value “true” if the first input parameter is equal to the second input parameter. This functoid requires two input parameters.
  • Looping: Use the Looping functoid to combine multiple records and/or fields in the source schema into a single record in the destination schema. This functoid needs at least one input parameter. There is no limit to the number of input parameters that the Looping functoid will accept. Only links are allowable as input parameters.

La idea es que Looping realiza las iteraciones de todos los elementos contenidos el record. Equal se usa para generar una salida lógica (True/False). La salida de la condición lógica se junta con la salida del Looping. Si el valor de la comparación lógica es verdadero, entonces se copia el registro al destino. Si es falso el registro se ignora.

Está es una simple implementación de un filtro en el Mapper.

La siguiente imagen muestra el mapa de ejemplo.

Ejecutar Procesos DotNet de manera Controlada

Se me plantea la siguiente necesidad:

"… tenemos un proceso complejo de trasferencia de datos entre dos sistemas construido en una aplicación de consola dotnet. Como es muy compleja, no podemos tocarla, es decir es un Pragma[1] para nosotros. Necesitamos controlar la ejecución de este proceso, es decir que se ejecute y si hay errores se notifique a los administradores…… ¿Qué podemos hacer?…."

Bueno, al ser una aplicación dotnet, la cosa se pone simple. Si usted nunca se ha detenido a considerar que significa que dotnet use código administrado, prepárese porque aquí va a disfrutar una de las ventajas de este tipo de código.

La solución más simple para esto es hacer que una aplicación que llamaremos "Controlador" sea quien ejecute el "Pragama" que llamaremos en este Post "Proceso". La idea es que el Controlador ejecute el Proceso en su mismo AppDomain[2] utilizando las facilidades que el Framewok da para ello. Esto se muestra en el siguiente código. Específicamente se usa el método ExecuteAssembly[3].

 

static
void Main(string[] args)

{


string[] strArgumentoControl= new
string[1];

 

Console.WriteLine("Ejecutar?");

Console.WriteLine("Ingrese Argumento de Control: ");

strArgumentoControl[0] = Console.ReadLine();


try

{


AppDomain.CurrentDomain.ExecuteAssembly(

@"..\Proceso\bin\Debug\Proceso.exe",null,strArgumentoControl );

}


catch (Exception X)

{

Console.WriteLine("Error: " + X.Message);

 

}

Console.ReadLine();

}

Código 1

Lo que hace esto es ejecutar en el mismo dominio de aplicación el Proceso, que está implementado en Proceso.exe. El tercer argumento del método los argumentos que se le pasan al programa que se está ejecutando.

Hasta ahora nada muy impresionante, esto es lo bueno. Si en el Proceso.exe se levanta una excepción (aspecto que dotnet maneja muy bien) está es atrapada por el Try/Catch del Controlador. Esto es porque los dos programan son código administrado y pueden compartir la información de las excepciones.

Veamos el Proceso de ejemplo, está en el código 2. Dependiendo del argumento que se le pase Proceso levanta diferentes Excepciones o termina de manera exitosa. Fíjense que no se controlan excepciones aquí, la idea es que si el proceso falla por cualquier motivo sea el Controlador quien se haga cargo.

 

class
Program

{


static
void Main(string[] args)

{

Console.WriteLine("Ejecutando Proceso Controlado……………");


switch (args[0])

{


case
"1":


throw
new Exception("Error Tipo Uno");


case
"2":


throw
new Exception("Error Tipo Dos");


case
"3":


throw
new Exception("Error Tipo Tres");


case
"4":


int iCero = 0;

Double dNada;

dNada = 100 / iCero;


break;


default:

Console.WriteLine("Todo Bien :)");


break;

}

Console.WriteLine("Terminó Proceso Controlado……………");

}

}

Código 2

 

Eso es todo, esto puede ser mucho más sofisticado agregando lógica en Controlador para que distinga los tipos de excepciones, notificaciones, reintentos, etc…etc…

El Código de ejemplo pueden descargarlo desde Aquí

Referencias

[1] Pragma, Pragma a diferencia de un sistema, es algo que se usa "por los bordes" Es decir no se comprende su interior.

[2] AppDomain, http://msdn2.microsoft.com/en-us/library/system.appdomain.aspx

[3] ExecuteAssembly, http://msdn2.microsoft.com/en-us/library/system.appdomain.executeassembly.aspx

¿Cómo hacer un gráfico con Barras y líneas en Reporting Services?

Hoy me preguntaron si se podía hacer en SSRS un gráfico que mostrara dos series de datos en barras y el promedio de las dos en una línea.

La respuesta es Sí.

¿Cómo se hace?

Es súper fácil, primero agregamos las dos series que estarán en el gráfico de barras. Por ejemplo costos y ventas, como muestra la ilustración 1.

Ilustración 1

Luego la idea es agregar una serie que saque el promedio de las dos series de barra y lo muestre como una línea. Para ello en las propiedades del gráfico, vamos a la pestaña Data y agregamos una serie de valores. Esto se muestra en la ilustración 2.

 

Ilustración 2

En el dialogo de creación de la serie se debe agregar el valor de la etiqueta a mostrar, por ejemplo "promedio" y el valor. En el valor usamos las capacidades de SSRS para calcular valores con la siguiente fórmula:

=Avg(Fields!HOras.Costo+Fields!Prom.Precio)

Por último para que esta serie se muestre como una línea y no una barra, como las otras dos, debemos seleccionar la opción Plot data as line como muestra la ilustración 3.

Ilustración 3

El resultado se muestra en la ilustración 4.

Eso es todo.

 

Salu2

Llamar un web servicies programado en java desde un Visual basic 6.0

Me llegó el siguiente mail:

 

Hola Juan Pablo:

Tienes alguna idea de cómo llamar un web servicies programado en java desde un Visual basic 6.0?
Si puedes ayudarme, te lo agradecería.
Que te tengas un buen día.

 

Por supuesto que se puede llamar un Servicio Web desde Visual Basic 6.0. No es tan fácil como se hace en dotNEt pero es posible.

Ahora que el servicio Web este hecho en Java, PHP, Piton, etc..etc… no tiene importancia ya que el propósito de los servicios Web es independencia de la tecnología que los implementa.

Puedes ver los siguientes links con ejemplos:

α.- Calling Web Services from Visual Basic 6, the Easy Way

β.- Microsoft Office XP Web Services Toolkit 2.0

γ.- HOW TO: Integrate a SOAP Toolkit Client with an Apache SOAP 2.2 XML Web Service

δ.- Sending SOAP Requests by Using the SOAP Toolkit 2.0 Client

 

Salu2

Medir el desempeño de Servicios Web plataforma DotNet.

 

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

  1. Web Serices, http://en.wikipedia.org/wiki/Web_services
  2. Serialización XML, http://msdn2.microsoft.com/es-es/library/90c86ass(VS.80).aspx
  3. Internet Information Services, http://es.wikipedia.org/wiki/IIS
  4. ISAPI, http://en.wikipedia.org/wiki/ISAPI
  5. HttpRuntime (Clase) ,

    http://msdn2.microsoft.com/es-es/library/system.web.httpruntime(VS.80).aspx

  6. HttpApplication ,

    http://msdn2.microsoft.com/es-es/library/system.web.httpapplication(VS.80).aspx

  7. HttpModules, http://msdn2.microsoft.com/en-us/library/zec9k340(VS.71).aspx
  8. WebServiceHandlerFactory Class,

    http://msdn2.microsoft.com/en-us/library/system.web.services.protocols.webservicehandlerfactory.aspx

  9. 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/

  10. Reflection (computer science), http://en.wikipedia.org/wiki/Reflection_(computer_science)
  11. Improving .NET Application Performance and Scalability,

    http://msdn2.microsoft.com/en-us/library/ms998530.aspx

  12. Working with Performance Counters,

    http://www.microsoft.com/technet/prodtechnol/acs/reskit/acrkch10.mspx

  13. Microsoft Application Center Test,

    http://msdn2.microsoft.com/en-us/library/aa287410(VS.71).aspx

BizTalk Server 2006 en alta disponibilidad

 

Un equipo de proyectos me mostró una propuesta de instalación de BizTalk para soportar alta disponibilidad y me preguntó si eso funcionaría.

La instalación de BizTalk era algo como se muestra en la figura 1. Es un balanceador de carga con dos nodos corriendo BizTalk y un cluster MSSQL 2005.

Ahora, la respuesta como siempre dice Dagum "depende". Voy a tratar de dar algunas luces de esto =) y asumiendo algunas cosas, evitar el depende.

Bueno, primero aclaremos algunas cosas. BizTalk Server 2006 está hecho por diseño para ser instalado en un ambiente "High Availability" [1].

La instalación de BizTalk Server en alta disponibilidad implica tener cada componente funcional en una instalación redundante. BizTalk server simplifica enfrentar estos escenarios separando conceptualmente las responsabilidades de almacenamiento de datos de las de procesamiento de estos. Por lo tanto, para tener una instalación de alta disponibilidad se necesitan correr múltiples Host de BizTalk contra un MSSQL en Cluster.

Fig1. Instalación BizTalk

Hasta ahora vamos bien. Avancemos un poco. ¿Qué pasa con la recepción de mensajes, orquestaciones y envío de mensajes si cae un Host de BizTalk?

Aquí hay que entender en concepto de Host y Host Instance de BizTalk Server antes de avanzar.

Un Host BizTalk es un contenedor lógico creado dentro de un BizTalk Server Group que puede contener objetos de BizTalk como Adapter Handler, recive Location (incluidos sus PipeLine) y orquestaciones. Típicamente se agrupan en un Host los objetos que son del mismo contexto de aplicación [3].

Una vez que se crean los Host (contenedores lógicos) estos se pueden asignar a diferentes nodos que tengan el servicio BizTalk corriendo, pasando a ser una "Host Instance".

La figura 2 muestra una instalación con dos nodos, 3 Host y 6 Host Instance que tienen como servidor de datos un cluster MSSQL. Un detalle de este ejemplo puede verse en MSDN [4].

Fig2. Instalación BizTalk de ejemplo con Host.

Ahora, qué diferencia hay entre el dibujo que se me presentó (Fig. 1) y la instalación la segunda instalación (Fig 2.). Principalmente dos puntos muy importantes.

Primero, en la segunda figura se presenta un esquema de Host BizTalk, que es la manera natural de hacer instalaciones en alta disponibilidad. Esto no está claro en el primer diagrama.

Segundo, en la primera instalación hay un SLB[3]. Si se trabaja con Host de BizTalk no es necesario usar un SLB porque BizTalk Server de manera automática distribuye la carga entre los múltiples nodos que corren una Host Instance. Esto es una muy buena solución! Pero tiene la limitante que si usted utiliza recepción de mensajes HTTP, SOAP o MSMQT va a necesitar un SLB para que los mensajes puedan ingresar a un Host por diferentes Host Instance.

Por eso, la respuesta por defecto "depende" sigue siendo válida, pero con un poco mas de información la respuesta podría ser categórica y precisa.

Referencias

[1] MSDN BizTalk Sever, http://msdn2.microsoft.com/en-us/library/aa560847.aspx

[2] MSDN BizTalk Server, http://msdn2.microsoft.com/en-us/library/aa577430.aspx

[3] Wikipedia, http://en.wikipedia.org/wiki/Load_balancing_(computing)

[4] MSDN ejemplo de instalación, http://msdn2.microsoft.com/en-us/library/aa578057.aspx