Saturday, July 27, 2013

Optimizando que es Gerundio



Proyecto

En Kinética llevamos tiempo trabajando en un proyecto que pronto saldrá a producción, es una herramienta web que va a tener un uso bastante mayor de lo que estamos acostumbrados en la oficina. Por este hecho y ante las altas previsiones del cliente hemos estado haciendo mejoras de rendimiento en la herramienta.

Hemos abarcado varios aspectos: el código, caché a distintos niveles y servidor.

Poniendo a punto


Quiero compartir con vosotros como hemos focalizado los esfuerzos y que podais ver los resultados con datos de tiempo. Quizás todavía tengamos margen de mejora pero creo que lo realizado hasta el momento es más que interesante. El objetivo también es mostrar cómo poniendo cuidado se puede poner al descubierto las principales fugas y atajarlas.


Herramientas

Para abarcar las mejoras hemos contado con dos herramientas principales.

PhpUnit - Que nos indicaba cuales eran los apartados más lentos de nuestra aplicación al mismo tiempo que nos avisaba si con alguna de las refactorizaciones nos cepillábamos alguno del resto de apartados.



PyLot - Una herramienta en Python que aunque no siendo definitiva ayuda a realizar unos test de stress del servidor suficientes para notar los cambios.


Entorno

Para los desarrollos web usamos CakePHP como framework. Una de las mejoras de la 1.3 a la versión 2 fué el cambio de SimpleTest a PHPUnit y una serie de mejoras para desacoplar algunos aspectos típicos de la programación web como es el servidor a la hora de creación de tests.



El otro apartado es el del servidor Apache, aunque tengo constancia de las mejoras, muchas de ellas no las comprendo en profundidad así que no haré mucha referencia a ellas. Quizás explique el uso de la herramienta Pylot en otra ocasión.


Punto de salida

-¡Oye chavales!, estamos previendo un uso más extenso del que teníamos planeado ¿cómo lo veis?

Tras un tiempo desarrollando preocupándote de que se cumplan las especificaciones, empieza la tarea de hacer que la herramienta sea usable(en términos de tiempo). Estamos trabajando con la herramienta a diario y va bastante fluida, pero claro hay que ver el contexto:

  • Trabajamos cada uno en local
  • Un solo usuario concurrente
  • Últimos añadidos a la aplicación por parte del cliente que hacen que las tareas más pesadas incrementen el tiempo de manera sustancial, cosa que hace llorar al niño Jesús

Así que hay que empezar a preguntarse cosas como ¿Qué pasa si se meten por ejemplo 50-100 usuarios a darle caña al servidor? Pues la triste realidad es que lo deja en bragas. El peor tiempo de petición llega hasta los ¡120 segundos! Sin lugar a dudas un despropósito.


¿Dónde mirar?

Tras ver las magnitudes de tiempo vemos que el principal escollo viene por la parte de código/mysql, miramos los tiempo de los tests y nos fijamos en aquellos tests que superen los 0,5-0,7 segundos, tenemos alguna función que llega a tardar la friolera de casi 7 segundos. Es ponerse a bucear en estos métodos para rápidamente encontrar algún que otro bucle anidado costoso y evitable así como consultas muy semejantes o incluso repetidas atacando a la base de datos.



Tras unos cuantos retoques vemos que la cosa mejora bastante bien, pero el problema principal  viene por un combo de la muerte, consulta a base de datos dentro de un bucle anidado. Es un método que en en pro del DRY se usa en varios sitios por lo que tan solo tenemos que hacer es modificar un poco el comportamiento para que mire en una caché a ver si tiene ya el dato consultado y antes de empezar el bucle hacer una consulta que obtenga y caché todos los resultados a necesitar. De manera instantánea los tiempo de la aplicación empiezan a descender.

Volviendo con el Pylot vemos como de los 120 segundos se ha reducido a 90. Todavía alto pero reduciendo.


Aligerando la carga de la base de datos.

CakePHP hace un uso intensivo por defecto de JOINs, toca repasar las principales tareas de la aplicación y muchas de ellas en detalle para darnos cuenta de que en muchos casos no estamos trayendo información no necesaria, recortamos estas consultas para traer lo necesario para hacer el trabajo.

¿Qué vemos que a lo largo de un método hacemos una consulta muy parecida o incluso repetida? Pues caché al canto. Los tiempos empiezan a ser aceptables, llegando a reducirse todas las tareas por debajo del segundo.


Tests en Servidores

En paralelo al proceso de optimización de código, se sigue avanzando en servidor. A medida que vamos avanzando por ambos lados vamos haciendo pruebas pertinentes para ver que vamos por el camino correcto.

De esta manera PyLot nos va chivateando tiempos de 60 / 40 / 20, todo ello pasito a pasito. Al mismo tiempo vamos probando con configuraciones en diferentes instancias de Amazon, combinando también con Amazon RDS para comparar con la bd local/remota.



Tras unos días, llegamos a unos valores máximos de 2 segundos en el servidor propio, lo que consigue que con las pruebas manuales las respuestas sean prácticamente instantáneas, en muchos casos tarda menos desde el servidor que desde local. Es de recibo decir que los tests de integración en servidor pasan algo más rápido que en local.


Reflexión.

Tras conseguir unas respuestas máximas de 120 segundos a 2 segundos estamos muy satisfechos, creemos que a partir de ahora es adecuar los parámetros de Apache con respecto a las usuarios que vayan entrando. Estos datos también hacen referencia a un servidor donde alojamos las aplicaciones de desarrollo y sus características no son nada especial. En caso de necesitar una alta capacidad se tiene que ir pensando en servidores más complejos con varios núcleos y aumentando los 2GB de RAM actuales.

Recompensa por trabajo bien hecho


En temas de código hay estructuras que definen fugas, los bucles anidados vienen siendo lo más típico. El tema de las consultas a base de datos son otra fuga, muy común es solicitar la misma información una y otra vez. El tema de la base de datos es también hiriente en Android con SQLite, hay que intentar agrupar/cachear las consultas más habituales o más pesadas.

Aparte de eso cada proyecto puede tener sus peculiaridades así que hay que hacer pruebas, cuantas más pruebas mejor, y que mejor que automatizar estas cosas. Los tests nos han sido realmente útiles.

Por comentar un consejo que nos llamó la atención pero acabo no afectando mucho en el rendimiento. En el caso concreto de la base de datos llegamos a un artículo donde nos indicaban la diferencias entre InnoDB y MyISAM, es una de esas cosas que nunca valoramos antes de empezar un proyecto nuevo.

Tienen objetivos distintos, pero en nuestro caso gracias a tener montados los tests no tuvimos que hacer mucha movida.

Debido a la estructura de tests que montamos comentado en un post anterior, pudimos rápidamente crear los tests con los tipos de motores, en nuestro caso las diferencias eran prácticamente imperceptibles.

No comments:

Post a Comment