XHGUI Pantalla principal

XHGUI: Entendiendo los informes de xhprof

En mi última entrada os presentaba dos proyectos Open Source que en conjunto nos ofrecen una herramienta bastante completa para realizar perfiles de memoria y consumo de CPU de vuestras aplicaciones PHP: xhprof y xhgui.

Como comenté mientras xhprof recoge los datos de nuestra aplicación, xhgui se encarga de almacenarlos en una base de datos MongoDB y formatearlos mediante una aplicación web. Pues bien, vamos a ir viendo paso a paso cada una de las pantallas y entendiendo los parámetros más importantes que en ellas aparecen.

Lo primero que nos encontramos al acceder a ella es un listado de las últimas ejecuciones monitorizadas (Recent Runs) ordenadas de forma descendente por la fecha y hora de cada llamada. Los datos que nos encontramos en esta pantalla son:

  • URL que ha sido monitorizada
  • Fecha y hora de la ejecución
  • Wall time (wt)
  • CPU time (cpu)
  • Memory usage (mu)
  • Peak Memory usage (pmu)

 

 

XHGUI listado principal

De todos estos parámetros puede que despiste un poco el término “Wall time“. Pues bien, este parámetro no mide nada más  que el tiempo total de ejecución, es decir, el tiempo que ha tardado el script al completo en ejecutarse. Por lo tanto este indicador incluye no sólo el tiempo que ha pasado nuestro script ejecutándose en la CPU, sino que también incluye tiempos de entrada/salida, llamadas a servicios externos, etc.

El parámetro cpu, mide el tiempo total de ejecución en cpu, teniendo en cuenta tanto el tiempo en espacio de usuario como en el de espacio de kernel del sistema operativo. Restando este tiempo al total (wt) tendremos una idea del tiempo que el script se ha pasado en otras tareas: entrada salida, esperas, etc.

La quinta columna (mu) nos muestra el total de memoria asignada a nuestro script por el motor de PHP, mientras que la última nos da la información de la cantidad de memoria asignada por el sistema a PHP (pmu).

Bien, una vez entendida esta pantalla ¿de qué nos sirve?. Pues bien, para ver un resumen de lo último ejecutado y poder elegir aquellas llamadas que llaman nuestra atención por alguna razón y poco más. Por ejemplo, si deseamos saber cuales han sido las llamadas que han tardado más o menos en ejecutarse, podemos pinchar en el título de la columna wt para ir cambiando el orden.

¿Y por donde empiezo? Pues bien, la navegación principal de la herramienta nos da pistas, sólo hay que ver los atajos predefinidos:

  • Longest wall time
  • Most CPU
  • Most memory

Estos atajos nos ofrecen el mismo listado que el principal pero ordenado por los scripts que más han tardado en ejecutarse, han consumido más CPU o más memoria, por lo que esto nos da una pista de por donde podemos empezar. Tomemos por ejemplo el listado “Longest Wall Time”:

XHGUI Mayor tiempo de ejecución

 

Si nos fijamos, tenemos dos candidatos para investigar: la llamada al raíz de la aplicación y a la desconexión de usuario, que ambas han tardado 6 segundos en responder (bastante para una aplicación usable).

¿Cómo ver “las tripas” de ejecución de estas llamadas? Pues haciendo click en la fecha y hora de ejecución del script, pasaremos a un informe detallado:

XHGUI informe detallado

 

En próximas entradas entraremos en detalle de este informe, que será uno de los que trabajaremos bastante con XHGUI, pero en líneas generales nos encontramos con:

  • En la columna de la izquierda: un listado de los parámetros y variables de entorno con los que se ejecutó el script
  • En la parte superior: un gráfico y listado de las clases y métodos que más tiempo de ejecución y memoria han usado
  • En la parte inferior del informe: un listado de todas y cada una de las llamadas realizadas por nuestro script

XHGUI detalle llamadas

 

En la próxima entrega entraremos empezaremos a analizar en profundidad este informe, comenzando por entender ciertos conceptos clave que mide xhprof. Mientras tanto os invito a que investiguéis por vuestra cuenta y vayáis jugando con la herramienta.

xhgui pantalla principal

XHGUI: realizar perfilado de tus php sin gastar dinero

XHGUI es aun un desconocido en el mundo PHP. Sin embarog todos los desarrolladores PHP saben de las maravillosas y excepcionales funcionalidades que ofrece Zend Server para poder detectar problemas en sus desarrollos: consumos de memoria alto, demasiado tiempo de ejecución de los scripts, problemas en el acceso a base de datos, etc, etc, etc.

Sin duda Zend Server es una herramienta de gran ayuda pero tiene un “incoveniente”: el coste de su licencia. Aunque para entornos de desarrollo es cierto que se podría trabajar con la versión gratuíta, ésta sólo mantiene información de las 24 últimas horas de ejecución de los scripts, lo cual puede ser un handicap para lograr encontrar la solución algún problema cuya localización no es inminente.

Después de bucear por la red buscando alternativas, he encontrado una extensión para PHP (liberada como Open Source por el equipo de ingeniería de Facebook en 2009) que nos da  una capa de captura de datos para realizar perfiles de consumo de CPU y memoria de los scripts PHP; su nombre: xhprof.

Como he dicho, la extensión xhprof  ofrece el API de captura de datos, por lo que si queremos que éstos sean útiles habrá que formatearlos de forma que sea fácil consultarlos. Aunque en el propio repositorio Github del proyecto nos ofrecen una aplicación PHP para procesar y mostrar esos datos, yo me he encontrado más cómodo instalando un proyecto paralelo que se llama XHGUI, también basado en PHP pero con una interfaz más moderna. 

Sí, está claro que ambos en conjunto no son Zend Server, obviamente, pero sí que cubre un amplio abanico de métricas que nos pueden ser de ayuda, y lo mejor de todo sin gastar un sólo €

La instalación de esta extensión es sencilla. Yo la he realizado en una Ubuntu 12.04.3 LTS en la que tengo PHP 5.5.4 compilado por mi como FPM y ha funcionado perfectamente. La extensión xhprof no tiene ningún pre-requisito especial y para instalar XHGUI aparte de tener un servidor web activo, necesitaremos MongoDB. Os recomiendo revisar las webs de ambos proyectos antes de la instalación, para verificar todo lo necesario.

Para instalar la extensión xhprof se hace uso de PECL:

Una vez finalizado el proceso de instalación hay que añadir la siguiente línea al fichero php.ini:

A continuación aquellos que tengan php como módulo de Apache tendrán que reiniciar el servidor web y quienes tengan PHP con FPM, como yo, deberán reiniciar el servicio:

Bien, ya tenemos la extensión cargada, ahora hay que instalar la interfaz gráfica. Creamos, por ejemplo, el directorio /var/www/xhgui:

Y en él he descargado el proyecto directamente de Github:

Una vez descargado seguimos las instrucciones para instalar las dependencias:

Bien, con las dependencias y todo instalado, he creado un virtualhost para acceder a la interfaz XHGUI. En el directorio /etc/apache2/sites-available creo el fichero xhgui con el siguiente contenido:

Una vez creado el fichero de configuración para este virtualhost, lo activamos y reiniciamos apache:

Y ya podemos acceder a nuestro virtualhost, pero veremos que no hay datos recolectados. Para ello, yo que tengo PHP con FPM he creado un pool de ejecución PHP que incorpora la cabecera de captura de datos que nos ofrece XHGUI.

De esta forma si necesito hacer profiling, sólo tengo que apuntar la ejecución de PHP en el virtualhost de la aplicación que quiero monitorizar a este pool y ya está; el resto, si no me interesa que se monitoricen se ejecutan en otro pool.

Para configurar el pool en /usr/local/php5/etc/fpm.d/ he creado el siguiente fichero:

En el que lo importante es la última línea en la que indico que se incluya el fichero /var/www/xhgui/external/header.php automáticamente al inicio de cualquier PHP que se ejecute en ese pool. Éste fichero se encarga de preparar el entorno para capturar datos.  A continuación en el virtualhost de la aplicación que quiero monitorizar incluyo lo siguiente para redirigir la ejecución de PHP al pool que me interesa:

¡Y ya está! Si entramos ahora a la aplicación que queremos monitorizar, y navegamos un poco, veremos que automáticamente comenzamos a tener datos en el panel de XHGUI:

xhgui pantalla principal

En el listado principal se nos muestra un listado de las últimas peticiones hechas al servidor con la URL de la llamada, la fecha y hora, el “wall time”, tiempo de uso de la cpu, memoria usada y pico de memoria del script. Si necesitamos más detalle, sólo tenemos que pinchar en el enlace que nos proporciona la fecha y  veremos detalles concretos de la llamada:

xhgui detalle perfilado

En próximas entradas entraré un poco más en profundidad en la interpretación de los datos y cómo localizar problemas en nuestro código. Espero que os resulte de ayuda.

Proyectos: cuadrando círculos

Muchas veces en el mundo del desarrollo de software (aunque es extensible a otras áreas) nos enfrentamos a proyectos de los que yo denomino de “Cuadrar Círculos“. Son proyectos en los que dentro de la lista de requisitos existen algunos que es difícil (o imposible) cumplirlos a la vez, pero por alguna extraña razón quien define (o paga) el proyecto decide que el sistema a desarrollar tiene que incluirlos sí o sí.

Da igual las razones que expongas para hacer ver que lo que te piden es un imposible o que en resumidas cuentas te están plantando como requisito la cuadratura del círculo. Eres del equipo de tecnología y tienes que conseguirlo que para eso estás ahí. En estos casos me acuerdo mucho del relato “Oír Gilipolleces“, concretamente del pasaje en el que el jefe le pide que desarrolle algo genérico y reutilizable pero a su vez específico.

En ese momento, el equipo de desarrollo se llena de resignación y se pone manos a la obra para diseñar una solución al problema. Normalmente esta decisión errónea lleva a continuas y eternas reuniones que yo llamo “del día de la marmota” (ya hablaré en otro post sobre ellas) en las que tras discutir, pintar innumerables esquemas, darle mil vueltas al problema, valorar cientos de soluciones y dejar secos una cantidad ingente de rotuladores siempre se llega a la misma conclusión: que cumplir todos los requisitos es prácticamente imposible o bien lleva a una solución extremadamente compleja. Además, esta búsqueda de lo imposible consume muchísimo tiempo y esfuerzo para nada.

Este tipo de proyectos son un gran peligro para cualquier organización, porque lo normal es que finalmente el equipo se salte todas las reglas o recomendaciones del departamento de arquitectura de software e implemente una solución compleja, difícil de mantener, con baja calidad y por lo tanto cara. Esto es peor todavía cuando los nuevos requisitos incompatibles se introducen como evolutivos de un proyecto ya implantado. En este caso lo normal es que se haga añicos la arquitectura correcta de la solución y se llene de parches, desarrollados en lo que yo denomino “modo ñapa“, incrementando innecesariamente el coste de mantenimiento.

Evitar estos problemas es a veces muy difícil porque en muchas ocasiones los responsables definir el producto no hacen un exhaustivo análisis de todas las implicaciones que cada requisito conlleva (o lo que es peor, no tienen el conocimiento ni la capacidad necesaria para poder hacerlo) pero tampoco permiten que el equipo de ingeniería proponga modificaciones al respecto… pero de esto último ya hablaré en otra ocasión, que es un tema que da para mucho 🙂

Not Invented Here: reinventando la rueda

En el mundo de las TIC hay personas, grupos o organizaciones que son reticentes a adoptar o usar todo aquello que no ha sido desarrollado por ellos. Son los seguidores de la llamada filosofía “Not Invented Here”.

Está claro que cada uno es libre de decidir su estrategia TIC (no hay verdades absolutas) pero este antipatrón tiene, según mi opinión, muchos peligros:

  • Tendencia a “reinventar la rueda”, es decir, desarrollar desde cero soluciones ya existentes y estandarizadas.
  • Sobre coste en los proyectos. Al dedicar tiempo a implementar lo que otras librerías o piezas de software externas nos pueden proveer estamos incrementando el coste del proyecto innecesariamente.
  • Curva de aprendizaje alta cuando incorporamos a un nuevo miembro al equipo de desarrollo. Cualquier persona nueva en el equipo tiene que dedicar tiempo en aprender aquellos frameworks y/o librerías antes de ponerse al día con el proyecto en sí.
  • Dificultad para externalizar el mantenimiento

Dentro de los seguidores del “no inventado aquí” hay un subconjunto que me parece muy peligroso y es el de aquellos que siguen esa filosofía sólo porque se creen los mejores, los más geeks y consideran que ninguna persona en el mundo es capaz de implementar la solución tan eficiente, escalable y fiable como lo harían ellos.

Estas personas desprecian cualquier otra solución porque “no se fían” de lo que otros implementan. Y ese “no fiarse” lo hacen por defecto, aun sin llegar a conocer realmente si esa solución es válida y cubre todas sus necesidades. Este grupo de personas que no atienden a razones, se convierte todavía en más peligrosos cuando dentro de la organización se les da poder de decisión y veto.

RabbitMQ como activar soporte en PHP 5.3.10 y Ubuntu 12.04

RabbitMQ es un sistema gestor de colas de mensajes de código abierto que implementa el estándar AMQP (Advanced Message Queuing Protocol). Su principal característica es que soporta multitud de lenguajes de programación (Java, PHP, Python, Ruby, .NET, etc) lo que lo hace más versátil que por ejemplo los sistemas de colas que sólo implementan JMS. Es muy sencillo de utilizar y ofrece bastantes modelos de distribución de mensajes que cubren prácticamente todas las necesidades en este sentido.

Detrás de RabbitMQ está VMware, empresa que en 2010 compró este sistema a Rabbit Technologies Ltd. y que a día de hoy da soporte al producto y da garantías de continuidad a este buen middleware ofreciendo incluso soporte comercial.

Además el protocolo de mensajería AMQP que implementa está respaldado por grandes corporaciones internacionales, que velan por la evolución del estándar y aseguran que no caiga en el olvido.

La instalación del servidor RabbitMQ en Ubuntu 12.04 es sencilla, basta seguir las instrucciones que se dan en su página para añadir el repositorio e instalarlo vía apt-get.

Un poco más complicado es activar el soporte de AMQP en PHP. Ya que Ubuntu no lo ofrece en sus repositorios de forma oficial. Aquí os presento los pasos que he dado en una Ubuntu 12.04 de 64 bits para tener el soporte activado.

PASO 1. Descargar el código de la última librería C para rabbit

Usando Git, nos descargamos la última versión del código de la librería C, que podemos obtener de git://github.com/alanxz/rabbitmq-c.git. Por ejemplo en nuestro home de usuario ejecutamos lo siguiente:


git clone git://github.com/alanxz/rabbitmq-c.git
cd rabbitmq-c
git submodule init
git submodule update

Esto nos crea un directorio rabbitmq-c en el que está todo el código y ficheros necesarios para compilar la librería.

PASO 2: Compilar e instalar la última librería C para amqp.


cd rabbitmq-c
autoreconf –i
./configure --enable-64-bit
Make
make install

Esto compila las librerías para una máquina de 64 bits y las instala por defecto en /usr/local/lib. Ojo que para la instalación es necesario que seamos usuario root.

Paso 3: Compilar e instalar el módulo AMQP para PHP 5.3 (versión 1.0.3 estable)

Debemos descargar la última versión estable del módulo (a fecha de este artículo la 1.0.3) y compilarlo.


wget http://pecl.php.net/get/amqp-1.0.3.tgz
tar –zxvf amqp-1.0.3.tgz
cd amqp-1.0.3
phpize
./configure --with-amqp=/usr/local/lib/ CFLAGS="-m64"
make
make install

Como en el caso anterior hay que ser usuario root para la instalación.

PASO 4: Configurar php para activar el módulo

Creamos en /etc/php5/conf.d/ un fichero amqp.ini con el siguiente contenido


; configuration for php AMQP module
extension=amqp.so

PASO 5: Probar

Creamos un pequeño script en php para probar que tenemos el soporte activado correctamente:


<?php

function testConsumer($envelope, $queue) {
 echo "Message : " . $envelope->getBody() . "\n";
 return false;
}

// Create a connection
$cnn = new AMQPConnection();
$cnn->setHost('localhost');
$cnn->setPort(5672);
$cnn->setLogin('php-amqp-user');
$cnn->setPassword('devpassword');

$cnn->connect();

// Create a channel
$ch = new AMQPChannel($cnn);

if ($ch->isConnected()) {

// Declare a new exchange
 $ex = new AMQPExchange($ch);
 $ex->setType(AMQP_EX_TYPE_FANOUT);
 $ex->setName('exchange1');
 $ex->declare();

// Create a new queue
 $q = new AMQPQueue($ch);
 $q->setName('queue1');
 $q->declare();
 $q->bind('exchange1', 'routing.key');

// Publish a message to the exchange with a routing key
 $ex->publish('message', 'routing.key');

// Read from the queue
 $msg = $q->consume('testConsumer');
}

Al ejecutarlo en consola debemos obtener lo siguiente si todo va bien, o si algo falla se generará una excepción PHP que nos aclarará un poco por donde van los tiros.


jcaride@devdesktop:~$ php -f test.php
Message : message
jcaride@devdesktop:~$