martes, 12 de marzo de 2013

Rastrear usos intensivos de CPU en aplicaciones web

En este artículo vamos a presentar una estrategia para intentar localizar problemas en aplicaciones web que se traducen en usos intensivos de CPU.

La estrategia aquí presentada no es la única posible, pero yo la he utilizado con éxito.

Antes de comenzar

Antes de hacer nada de lo que se expone en este artículo, es necesario destacar que durante el periodo de análisis de la aplicación web se producen momentos de mucho ‘stress’ en el servidor de aplicaciones, con lo que es fundamental que todas estas pruebas se realicen en un entorno aislado en el que se haya podido reproducir el problema.

Además para facilitar la tarea es recomendable que el pool de aplicación asignado a la aplicación web esté dedicado únicamente a ella, ya que de lo contrario se puede generar un ruido innecesario.

Un punto fundamental antes de comenzar es que tenemos que haber conseguido previamente reproducir el problema; esto quiere decir que la manera más eficaz de realizar este tipo de análisis es siendo capaces de provocar el uso intensivo de CPU.

Requisitos

Para poder analizar la información necesaria para localizar el problema, necesitaremos una serie de herramientas (gratuitas) que necesitaremos instalar por un lado en el servidor web y por otro en el equipo donde realizaremos los análisis (si es distinto del servidor)

Herramienta

URL Descarga

Cliente / Servidor

Debug Diagnostic Tool 1.2

Enlace externo

Servidor

WinDbg

Enlace externo

Cliente

SOS.dll

Disponible en la carpeta del Framework 2.0

Cliente

La instalación de la herramienta de diagnóstico “Debug Diagnostic Tool 1.2” puede ser un poco “enrevesada” ya que tiene reconocidos problemas cuando se instala en un equipo que no esté en inglés. Para las instrucciones de instalación en este tipo de sistemas, podemos consultar el artículo correspondiente publicado hace un tiempo [acceso].

Captura de información

Lo primero que tenemos que hacer es capturar la información necesaria para realizar posteriores análisis e intentar determinar el origen de los problemas. Esta información se recoge en forma de “volcados” o “dumps” y se realizará en el servidor mediante la herramienta “Debug Diagnostic Tool 1.2”

Pasos para realizar el volcado correctamente:

1. Realizamos una llamada a la aplicación web para que se inicie el proceso ‘w3wp’ correspondiente, por si acaso.

2. Iniciamos sesión en el servidor.

3. Abrimos la consola de IIS, seleccionamos el servidor y hacemos doble clic en “Procesos de trabajo” en la sección de la derecha correspondiente a “IIS”
clip_image001

4. En la ventana que se abre aparecen todos los pools de aplicaciones que están activos, tendremos que apuntar el ID del proceso que nos interesa (el correspondiente al pool de aplicación de nuestra aplicación web)
clip_image002

5. Arrancamos la herramienta “Debug Diagnostic Tool” y cancelamos la ventana emergente que aparece.

6. Vamos a la pestaña “proceses” y localizamos el correspondiente al ID obtenido anteriormente.
clip_image003

7. Realizamos las operaciones necesarias en la aplicación web hasta conseguir que se dispare el uso de CPU

8. En el momento en el conseguimos el comportamiento incorrecto, tenemos que realizar un volcado de memoria mediante la herramienta de Debug. Para esto, hacemos clic con el botón derecho del ratón sobre el proceso y seleccionamos “Create full user dump”
clip_image004

9. Una vez finalizado el volcado, nos aparecerá el siguiente mensaje, indicando además en qué ubicación de disco se ha generado dicho volcado.
clip_image005

10. Listo, hemos generado el volcado correctamente

En ocasiones en función del grado de uso u ocupación del proceso, es posible que en lugar del mensaje de éxito nos aparezca un mensaje de que NO se ha podido generar el volcado. Esto suele suceder porque llegado un grado “X” de uso, el pool se recicla como parte de su configuración anti-errores. Para evitar que esto nos afecte, tendremos que cambiar ese comportamiento en la “Configuración avanzada” del pool de aplicación, la opción aparece destacada en la siguiente captura:

clip_image006

Si la protección rápida está habilitada y se produce el problema mencionado, bastará con deshabilitar esa opción de manera temporal.

Analizando la información

Una vez que hemos conseguido el volcado del proceso, llega el momento de analizarlo para intentar localizar los puntos de ‘conflicto’

Es necesario destacar que este proceso no es una ‘ciencia exacta’ por lo que tal vez no obtengamos información útil, pero al menos es una posibilidad muy a tener en cuenta.

El análisis de los volcados lo realizaremos con la herramienta “WinDbg”, pero antes tenemos que realizar una pequeña configuración:

1. Abrimos la carpeta del ‘Framework’ donde está la dll “SOS.dll” especificada en la tabla del punto 5.

2. Copiamos esa dll a la carpeta de instalación de “WinDbg”. Esta librería es necesaria porque proporciona información sobre el entorno interno del CLR.

3. En una carpeta del equipo donde realizaremos el análisis, creamos una carpeta “symcache” (será utilizada por el depurador para desargar los símbolos de los archivos PDB’s) en este documento se asume que la carpeta existe en la ruta c:\symcache

Para analizar el volcado, seguimos los siguientes pasos:

1. Arrancamos la herramienta WinDgb

2. Cargamos el archivo de volcado, mediante el menú “File”, “Open Crash Dump”

3. Una vez cargado el archivo, ejecutamos los siguientes comandos:

a. .symfix c:\symcache

b. .reload

c. .load sos

4. Obtenemos todos los procesos recogidos en el volcado con el comando !runaway, que nos dará un resultado como este:
clip_image001[5]
En esta lista, ordenada por tiempo de CPU, podemos observar qué procesos están haciendo un mayor uso de la CPU. En la captura anterior, vemos que son los procesos con ids 27 y 23

5. Comprobamos que los hilos ‘sospechosos’ pertenecen a procesos de .Net, con el comando !threads:
clip_image003[5]
La imagen se ve pequeñita, pero se confirma que uno de los hilos ‘sospechosos’ es un hilo ‘manejado’ por el CLR.
Además, podemos ver que uno de los hilos que aparecen está en un estado de “excepción”. Un vistazo de los dos hilos implicados, releva el estado de la ejecución:

a. Hilo 27: System.Threading.ThreadAbortException

b. Hilo 25: System.CannotUnloadAppDomainException

6. A continuación, ‘navegamos’ a los hilos con el comando ~27s y ~25s (el formato es ~[#hilo]s

7. En cada uno de ellos, obtenemos la pila de llamadas con el comando !clrstack. Con esta pila podemos intentar averiguar qué está pasando en la aplicación.

Como complemento al documento, se añaden las capturas de los hilos y la conclusión que nos han permitido obtener.

Detalle del hilo “27”

clip_image004[5]

Detalle del hilo “25”

clip_image006[5]

Conclusiones

Con la información que hemos obtenido, podemos determinar que la aplicación en cuestión ha intentado descargarse de memoria (System.AppDomain.Unload en el hilo 25) pero que existe un hilo (el 27) que está ocupando mucho tiempo de CPU al hacer:

Oracle.DataAccess.ClientOracleTuningAgent.DoScan().

En esta ocasión, podemos interpretar que existe algún problema con el Cliente Oracle. Una búsqueda en google nos da el siguiente enlace, que avala nuestra teoría [acceso].

Extracto de la página:

“This has been resolved. The fix is released in Oracle 11.2.0.1.2, which is available through the oracle.com website”

lunes, 25 de febrero de 2013

Instalar la herramienta Debug Diagnostic Tool v1.2

Sin morir en el intento

Problema

Tenemos una aplicación web que está teniendo un uso excesivo de CPU en determinadas ocasiones, pero que no estamos pudiendo determinar cuándo o más importante, por qué, está haciendo ese uso intensivo de CPU.
Para revisar la aplicación decidimos descargar e instalar esta herramienta, disponible [aquí].
Comenzamos la instalación (siguiente, siguiente siguiente) y de repente:
image
Después de buscar mucho por aquí y por allí, lo que encontramos es que es un problema con el soporte multiidioma del instalador de la herramienta. Lo cierto es que es bastante triste, pero el instalador requiere que exista un grupo ‘Users’ en la máquina de instalación, y como en este caso la máquina de instalación está en español, ese grupo, pues no existe. Triste triste.

La solución

Pues no se trata de una solución como tal, más bien de un ‘workaround’ que nos permitirá instalar y ejecutar la herramienta sin problemas.
  1. Vamos a la Administración del Equipo
  2. En la sección de grupos locales, creamos un grupo que se llame “Users” y en el incluimos el usuario con el que hayamos iniciado sesión en la máquina.
  3. Damos permisos de control total a este grupo en la carpeta de instalación.
  4. Instalar la herramienta.
En este punto es posible que nos de otro error diciendo en la fase de “Removing backup files”. En este punto, si le damos a continuar la instalación NO se realiza y además borra los archivos que hubiera copiado originalmente. Para solucionar este problema, cuando nos dé este error:
  1. Antes de pulsar el botón, vamos a la carpeta de instalación (por defecto “C:\Program Files\DebugDiag”) y copiamos el contenido llevándolo a una ubicación temporal.
  2. Le damos al botón de finalizar en la ventana de error y nos borrará el contenido de esa carpeta
  3. Movemos los archivos de la ubicación temporal a la carpeta de instalación.
  4. Ejecutamos de nuevo la instalación.
SOLUCIONADO.
No preguntéis por que, porque no lo sé, pero bajo mi humilde opinión es una ‘cagada’ con todas las letras por parte de Microsoft, además de ser incomprensible. Por supuesto, una vez instalada la herramienta podemos eliminar el grupo creado sin problemas.

jueves, 22 de noviembre de 2012

Visual Studio no lanza todas las excepciones del código

Hoy me ha pasado una cosa un poco extraña relacionada con la gestión de excepciones.

El problema

Tenemos un formulario de Windows con una caja de texto en la que en el evento “TextChanged” realizamos una serie de operaciones, llamando para ello a un método externo.

El tema es que en un momento dado, me he fijado que en el método externo se estaba produciendo una excepción, pero en depuración no me estaba mostrando la típica ventana de excepción no controlada… Vamos, que no me estaba enterando de que había un problema con el código.

Para reproducir este comportamiento, basta con añadir una caja de texto a un formulario y codificar en el manejador del evento “TextChanged” una llamada a una función que produzca una excepción, por ejemplo:

image

Ejecutamos el formulario y escribimos algo en la caja de texto.

¿Aparece esta ventana?

image

Entonces no tienes el mismo problema que yo y te has equivocado de post…

Lo que a mí me pasaba, es… nada. No da ningún tipo de excepción al trabajar con el formulario en cuestión. entonces, ¿cómo sabemos que hay una excepción? en la ventana de “Output” aparece la siguiente entrada:

image

Una explicación (rapidita)

Por lo visto, este comportamiento es así por diseño, siempre que estemos ejecutando Visual Studio en un sistema en 64 Bits (como es mi caso) cuando la excepción se produce en un método que cause una transición al kernel (como por ejemplo el manejador en cuestión, esta excepción se trata en el propio kernel y se atrapa por el sistema operativo. Como la excepción ya ha sido controlada, lo que sucede es que nosotros no nos enteramos.

Para más detalle, entiendo que Google estará encantado de ayudarnos.

Una solución (más bien alternativa)

Para conseguir que el depurador de Visual Studio nos avise de esas excepciones, tenemos que indicarle explícitamente, en la ventana de “Exceptions”

image

Esta ventana aparece en el menú “Debug”, “Exceptions…” y para evitar el comportamiento que he explicado, basta con marcar la casilla “Thrown” del grupo “Common Language Runtime Exceptions”

Una vez marcada la casilla, cuando llega al punto de la excepción, ya nos aparece la ventana de excepción no controlada que necesitamos. De esta manera ya no se nos “enmascaran” posibles errores…

¿Por qué digo que es una alternativa?

Un efecto colateral de esta configuración es que a partir de activar la opción, cada vez que de una excepción (sea controlada o no) nos va a aparecer la dichosa ventanita, deteniendo el depurador hasta que le demos a continuar.

Esto en condiciones normales es un auténtico problema, pero yo considero que me merece la pena el inconveniente, sobre todo si trabajamos con ‘rethrowing’

Último apunte

El problema expuesto aquí no genera ningún problema adicional en el código desarrollado, ya que si en lugar de arrancar el depurador ejecutamos el archivo compilado o lanzamos la ejecución SIN depuración (Ctrl + F5) la excepción no controlada SÍ que aparece aunque, claro, con la apariencia que nadie queremos en nuestros programas

image

martes, 6 de noviembre de 2012

Trabajando con NuGet–Un inicio

¿Qué es NuGet?

NuGet es una extensión de Visual Studio que hace que sea fácil agregar, actualizar y elimina bibliotecas (implementadas como paquetes) en un proyecto de Visual Studio. Un paquete de NuGet es un conjunto de archivos empaquetados en un solo archivo con extensión .nupkg que usa el formato Convenciones de empaquetado abierto (OPC).

(Copiado íntegramente del MSDN)

¿Qué hace falta?

Lo primero, instalarlo.

En Visual Studio 2010 se instala mediante el administrador de extensiones (Menú Tools, Extension Manager) mientras que Visual Studio 2012 lo trae instalado por defecto.

Una vez instalado, basta utilizar los nuevos menús (Manage NuGet Packages)

Esta herramienta es brutal, pero lo verdaderamente brutal sería poder crear nuestro propio repositorio de paquetes de NuGet, de forma que en la organización tuviéramos todos los componentes homologados disponibles para su utilización, actualizables además muy fácilmente.

En el artículo indicado anteriormente tenemos las instrucciones básicas, que a continuación intentaré explicar un poco más si es necesario.

Generar un servidor NuGet

No es necesario generar un servidor de NuGet para poder trabajar con un repositorio particular de paquetes, pero considero que es importante y útil como para al menos indicarlo.

Sencillo:

  1. Creamos una aplicación web ASP.NET (4.0) vacía en Visual Studio.
  2. Instalamos el paquete de NuGet “NuGet.Server”
  3. Publicamos la aplicación en un servidor web.
  4. Publicamos en la carpeta “Packages” los paquetes de NuGet que queramos que estén disponibles.

Añadir una ruta de paquetes en Visual Studio

Para configurar Visual Studio de forma que pueda conectar al repositorio, tenemos que ir a Herramientas, Opciones, y añadir un nuevo origen de paquetes en la ventana:

image

Generar un paquete de NuGet

Para generar nuestros propios paquetes para NuGet, podemos hacerlo mediante línea de comandos (descargando nuget.exe) o podemos hacerlo con un interfaz gráfico (descargando el “NuGet Package Explorer”) se trata de una aplicación click-once, con lo que se actualizará automáticamente.

A continuación vamos a ver los pasos necesarios para generar un paquete con el cliente click-once.

  1. Arrancamos el “NuGet Package Explorer”
  2. Elegimos la opción “Create a new package”
    image
  3. En la parte de la izquierda editamos los metadatos del paquete (Menú Edit, Metadata)
  4. En la parte de la derecha arrastramos en ensamblado que queremos empaquetar.
    image
  5. Guardamos el paquete en la ruta deseada con el menú File, Save o podemos exportarlo con el menú File, Export…

En el momento de generar el paquete podemos además indicar las dependencias que nuestro paquete tenga con otros componentes. Para añadir una dependencia, hacemos clic en el botón “Edit dependencies” en la parte inferior de la sección izquierda (donde hemos puesto la información del paquete)

  1. Añadimos un nuevo grupo con el botón con el símbolo “más”
    image
  2. Ahora hacemos clic en el botón con el icono de propiedades para elegir una dependencia alojada en un repositorio, y la seleccionamos con doble clic (en la siguiente captura, seleccionamos el paquete de log4net)
    image
  3. Confirmamos haciendo clic en el botón de añadir nueva dependencia (a la derecha de la caja con la versión del componente)
    image
  4. Confirmamos con “OK” y ya tenemos la dependencia creada.

Al añadir una dependencia, lo que conseguimos es que cada vez que se instale el paquete, automáticamente se instalen también las dependencias configuradas.

Otra opción interesante es hacer ‘transformaciones’. Esto significa que podemos configurar el paquete para que actualice archivos presentes en el proyecto, por ejemplo el archivo App.config.

Para esto, en la sección de “Package contents”

  1. Añadimos la carpeta para contenido (menú Content, Add, Content Folder)
    image
  2. Sobre la carpeta “content” añadimos un nuevo archivo con el botón derecho del ratón y, muy importante, le damos al archivo el nombre del archivo que queremos modificar, terminado en “.transform”
    image
  3. Esto genera un archivo vacío, en el que incluiremos el contenido que deseamos que se añada al configurar el paquete en el proyecto, en la siguiente captura se puede ver el contenido necesario para el correcto funcionamiento del paquete ‘log4net’
    image

Una vez hecho todo esto, cuando configuremos el proyecto para utilizar el paquete, automáticamente añadirá las entradas especificadas en el archivo de configuración.

Actualizar un paquete de NuGet

Realmente no existe el concepto como tal de actualizar, realmente lo que hacemos es un “Save as” del paquete anterior, modificando la versión en la sección de “Package Metadata”. Al hacer el “Save as” nos propone el nombre original actualizado con la nueva versión, y una vez en la solución, si hacemos clic con el botón derecho del ratón sobre la solución y elegimos “Manage NuGet Packages for Solution” veremos que tenemos nueva versión del paquete, y podremos actualizar todos los proyectos de la solución de un plumazo.

image

image

Ultimas consideraciones

Existen más posibilidades al generar paquetes, como por ejemplo publicar distintas versiones de los ensamblados para distintas versiones del Framework, pero de momento no vamos a entrar más a fondo, como primera aproximación es suficiente.

miércoles, 17 de octubre de 2012

Pruebas de software–Recursos

Un listado rápido de presentaciones acerca de las pruebas de software, un poco más de información aparte de la clásica de caja blanca / negra, de humo, etc. Todas en castellano y disponibles libremente en ‘www.slideshare.net

  • Tipos de pruebas de software: 32 transparencias detallando de forma muy clara un gran número de tipos de pruebas, desde las unitarias hasta las pruebas beta. Acceso.
  • Introducción a las pruebas de software: Fundamentos, metodología y tipos de pruebas a lo largo de 57 transparencias, incluida bibliografía y sitios de consulta. Acceso.
  • Fundamentos de pruebas: Muy completa, tratando los fundamentos de las pruebas, pruebas a través del ciclo de vida del software, técnicas estáticas y el proceso del software, técnicas de diseño de pruebas y gestión de pruebas, todo ello a través de 119 transparencias. Acceso.

 

Si encuentro algo más interesante a nivel teórico, iré actualizando la lista, y como he comentado en alguna ocasión, si alguien entiende que estos enlaces no deben estar publicados aquí, no tiene más que dejar un enlace y tomaré las medidas adecuadas.

martes, 25 de septiembre de 2012

Cómo hacer funcionar un servidor de compilación de TFS 2010

Sin morir en el intento

Situación inicial

Pongamos que tenemos una instalación nueva, limpia, de un sistema TFS 2010, con su servidor de Base de Datos, su servidor de TFS 2010, y ahora queremos instalar una máquina para las compilaciones.

Sin problemas ¿no? instalamos la parte del servicio de Builds desde el DVD de TFS 2010 y listo (bueno, listo no, primero lo tenemos que enganchar al servidor de TFS, pero hasta aquí es tal y como pone en toda la documentación de Microsoft)

El problema

Una vez instalado y configurado, generamos una nueva definición de Build, así como lo hemos hecho siempre, sin nada especial, y la lanzamos. El resultado:

image

Otro que nos puede también aparecer (este relacionado con la compilación en 32 ó 64 bits):

image

Y por supuesto alguno más, como el mensaje del “Tracker.exe” del que ya hablé aquí.

[modo enfado ON]

Puedo entender que cuando montamos un sistema de compilación existan determinados tipos de proyectos que de partida no podamos compilar sin alguna configuración ‘especial’ (por ejemplo los de Sharepoint) o que si el proyecto utiliza componentes de terceros haya que realizar alguna operación especial, pero ¿cómo es posible que no sea capaz de compilar un mini proyecto de prueba sin nada especial?

O por lo menos, en la documentación que lo avisen: “Instalar únicamente el servidor de Compilaciones NO permite compilar proyectos”.

[modo enfado OFF]

En fin, es lo que hay. ¿cómo lo solucionamos?

La solución

El mensaje de error de la compilación nos da varias opciones para solucionar el problema (en este caso el del “resgen.exe”)

  1. Install the Microsoft Windows SDK. 
  2. Install Visual Studio 2010. 
  3. Manually set the above registry key to the correct location. 
  4. Pass the correct location into the "ToolPath" parameter of the task.

Vamos a ver, si es obligatorio tener instalado algún SDK o el Visual Studio, ¿por qué no lo dicen en ningún sitio? Que no lo digo por no instalar, lo digo por la cara de tonto que se te queda…

En mi caso, lo que mejor me venía era instalar el SDK de Windows, en concreto “Microsoft Windows SDK for Windows 7 and .NET Framework 4

Una vez instalado, ya compila correctamente.

Nota mental

Es muy posible que al intentar compilar un proyecto web aparezca el siguiente mensaje:

image

Esto es porque no hemos instalado el Visual Studio 2010, para solucionarlo sin necesidad de instalar este producto, basta con instalar el Team Explorer en el servidor de Compilación.

De hecho, en muchas páginas que he consultado para estos problemas recomiendan instalar Visual Studio en la máquina de compilación, que además no consume licencia… Igual es lo más fácil.

jueves, 20 de septiembre de 2012

Error al publicar una aplicación mediante ClickOnce con Visual Studio 2010

Una rápida, que me acaba de pasar y que si no lo apunto, la siguiente vez que me pase lo mismo estoy todo el día mirando por qué.

El problema

Abrimos una solución con Visual Studio 2010, vamos a las propiedades del proyecto que queremos publicar mediante ClickOnce, y le damos al botón “Publish” (o al “Publish Wizard”, realmente sucede lo mismo); resultado de la publicación:

image

¿Cómo?

A ver. Compilamos la solución y compila bien, volvemos a compilar todos los componentes y compilan bien, intentamos hacer la compilación y… el mismo error.

La solución

Voy a ir directamente a la solución, ya que no tengo explicación para este comportamiento:

1.- En el Solution Explorer, localizamos el proyecto.

2.- Sobre el proyecto, clic con el botón derecho del ratón, “Publish”

image

¿El resultado?

image

Que alguien me lo explique, por favor.