2009/08/10

Rendimiento en Drupal (II)

Sobre el tema que ocupaba en el anterior post, continuamos.
El site se diseñó sobre Drupal 5.x, el cual aunque tiene importantes mejoras de rendimiento sobre las versiones 4.x, no llega a lo que puede dar de sí 6.x o incluso la 7.x, actualmente en desarrollo.
Es por ello que tuvimos que implementar una serie de mecanismos para reducir el impacto sobre el hardware disponible. Estos fueron los mecanismos implementados.

- Uso intensivo de memcache. Memcache es un sistema de cachés en RAM, como su nombre indica. Se utilizó para evitar queries masivas sobre la base de datos (mysql). Drupal utiliza la base de datos para prácticamente todo. El ir añadiendo módulos y bloques hace que este uso sea tremendamente intensivo. Esto puede llegar a crear un gran problema. Memcache lo que hace es cachear las queries más habituales en una gran tabla hash, lo que reduce a la mínima expresión (updates e inserts) los accesos a BBDD. El impacto de memcache sobre el site fue brutal, especialmente a nivel de BBDD.
- Uso de las cachés internas de Drupal. Drupal 5.x tiene un sistema propio de cachés. Genera un expires en las páginas, de forma que el usuario que navegue no las recargue cada vez que pase por el site. En 5.x este sistema se limita a eso y poco más. En la versión 6.x se cachea por bloque, lo que produce un importante incremento del rendimiento, pero no así en la 5.x. Además, cada vez que un usuario registrado accede, se limpia la caché. Una lástima. Existen algunos módulos interesantes, como "Advanced Cache" (advcache) que mitiga parte del problema, o Block Cache que fue incluído en Drupal 6.x como caché de bloques. En nuestro caso, utilizamos una versión desarrollada a medida y más flexible de block cache para reducir la carga de site, la cual resultó muy beneficiosa.
- Uso de un proxy reverso. En este caso, squid 2.6. Un sistema de caché reversa puede salvar el pescuezo a cualquiera. Al contrario que la caché interna de Drupal que cachea principalmente objetos, el proxy reverso cachea las páginas renderizadas tal cual, así como los gráficos, css, javascript, etc. Si bien estos últimos apenas suponen carga para el servidor web, sí que implican el uso de procesos, escrituras del log, etc, etc. El cacheo de páginas renderizadas libera realmente al site de producción. En nuestro caso, modificamos drupal para generar dos tipos de URL. Una URL genérica para usuarios anónimos, y una URL con un parámetro para usuarios logados, de forma que el sistema de caché reversa cacheara todos los accesos anónimos (segun drupal indicara en su expires) y liberara de los mismos al servidor. Los usuarios logados seguían cargando (y mucho) el site, pero al menos crawlers, usuarios ocasionales (la gran mayoría) ya no lo hacían.
- PHP eaccelerator. Es un acelerador de PHP. Básicamente lo que hace es almacenar el código PHP ya compilado para que el sistema no tenga que volver a interpretarlo cada vez que una página es invocada. El rendimiento del código se incrementa entre x3 y x5. Hay otros sistemas como APC o Xcache que tienen un impacto similar.
- En MySQL, cambio de MyISAM a InnoDB. Soy poco fan de MySQL y siempre me ha parecido que postgres es un sistema de BBDD mucho más robusto, fiable y serio. Pero es lo que hay. Como estábamos trabajando con MySQL 5, teníamos posibilidad de usar InnoDB en lugar de MyISAM como sistema de almacenaniento. Aunque sobre el papel MyISAM es más rápido a la hora de realizar consultas por su mayor simplicidad, InnoDB es mucho más avanzado por cuanto que no bloquea tablas completas en consultas o updates. En nuestro caso, además, prácticamente no usamos las consultas porque memcache las sirve casi todas, y experimentamos bloqueos por queries un tanto "rudas" contra la BBDD que en algunas ocasiones colgaron el sistema. El paso a InnoDB solucionó este problema. Modificamos algunos puntos del código para eliminar bloqueos explícitos que realiza Drupal 5, pensado para MyISAM, en aras de mejorar el rendimiento, aunque como supondréis mucho, poco incrementó dicho rendimiento habida cuenta de que (otra vez) casi todo se lo come memcache.

Adicionalmente a estas medidas, y como red de seguridad, sugerimos una serie de cambios al proveedor (sí, lo sé, esto no debería haber sucedido jamás, pero el mundo de los sysadmins está lleno de manías y no es fácil decirle a uno lo que tiene que hacer. A todos nos sienta mal que nos lo digan).
- Limitar el número de procesos de Apache (para evitar que el servidor se sature). Mejor hacer esperar al usuario unos segundos encolado, a hacerle esperar para siempre porque nuestro servidor se ha ido a freir monas. Aquí lo ideal es realizar un estudio a grosso modo entre la memoria utilizada por proceso, la memoria de la máquina y la potencia de CPU de la máquina. Esto es, si cada proceso viene a tomar 100MB, tenemos una máquina con 2GB de memoria y un procesador doble núcleo, no parece lógico coger más a allá de 15 procesos en Apache para no quedarnos sin memoria... o sin CPU, si la aplicación es muy intensiva.
- Limitar el número de conexiones a BBDD. Tanto a nivel de gestor como a nivel de php. En este caso, si como máximo vamos a tener 15 procesos, no tiene sentido dar más de 15 conexiones a BBDD. Como siempre, mejor "encolar" que ser "enculados" (no tiene gracia, pero bueno).

Con estos cambios más algunos a nivel de código que realizaron los desarrolladores (desde la parte de administración IT podemos hacer muchas cosas para mitigar, pero a fin de cuentas muchos de los problemas, si no casi todos -que no ha sido en este caso-, se solucionan desde la pantalla del programador) conseguimos que lo que fue una abrupta salida en producción se convirtiera dos días después solo en un problema, y al cabo de dos semanas en un problemilla.

Todavía hay muchas mejoras que se pueden hacer, sobre todo a nivel de cachés de Drupal y optimización de algunos componentes internos, pero a nivel de IT poco más se puede hacer. Y si alguien tiene alguna sugerencia que me la diga, que estoy completamente abierto a nuevos planteamientos.

2 comentarios:

  1. tengo un problema con las cabeceras cuando activo el caché de drupal como lo soluciono?

    ResponderEliminar
  2. Obviamente, primero tendrás que identificar cuál es el problema con las cabeceras y modificar el código a tal efecto.
    Con la nula información que das poco puedo hacer por echarte una mano, la verdad.
    Y por otro lado no soy desarrollador, así que las modificaciones a nivel de código, aunque las pueda realizar, no son mi fuerte.
    Si te has leido el artículo, va orientado principalmente hacia la mejora de la arquitectura del sistema, sin tocar drupal.

    ResponderEliminar