Alquimia Proyectos Digitales

Empresa de consultoría y desarrollo web Drupal | Barcelona

Mejorar el rendimiento de Drupal usando gettext nativo para el sistema de traducciones

Hoy vamos a presentar un método para mejorar el rendimiento de un portal o aplicación web Drupal. Consistirá en hacer que el código de Drupal core use la extensión Gettext de PHP para obtener las traducciones de cadenas de ficheros con formato gettext nativo (.mo). Esto permite reducir las consultas a base de datos y a las tablas de caché, mejorando el rendimiento y la escalabilidad de la web.

Como dice la documentación de PHP:

"La función gettext implementa el API del NLS (Native Language Support). Puede ser usuado para internacionalizar sus aplicaciones en PHP."

Drupal no utiliza esta extensión de PHP para el sistema de traducciones, sino que implementa su propio sistema de almacenar y presentar las cadenas en distintos idiomas.

Como resumen rápido, nuestras pruebas muestran de forma consistente mejoras de rendimiento que dependiendo de las circunstancias pueden variar entre un 10 y un 60 por ciento.

Como se almacenan las traducciones en Drupal

Drupal almacena todas las traducciones en tablas de la base de datos. Para no tener que hacer una consulta por cada traducción, el sistema de traducciones saca con una consulta de la base de datos todas las traducciones de longitud menor a 75 caracteres.

Este bloque inmenso de traducciones se almacena posteriormente en caché y es regenerado cada vez que se encuentra una traducción nueva.

Esto tiene las siguientes desventajas:

  • La extracción de las traducciones de la base de datos para generar la caché se hace mediante una consulta muy costosa.
  • El registro de traducciones en la caché es bastante grande y esto afecta al rendimiento y la escalabilidad de la web.
  • Si un proceso encuentra que no tiene las traducciones en la caché y que no puede regenerarla (porque ya lo está haciendo otro proceso), hará una consulta por cada traducción que haya que imprimir en el sistema.

Como se puede ver, el sistema de traducciones de Drupal tiene algunas inconsistencias que pueden perjudicar el rendimiento. La solución que presentamos aquí evita estos problemas en los casos en que pueda aplicarse.

El enfoque Gettext

El parche es muy simple: cuando Drupal inicia el sistema de traducciones se comprueba si está disponible el fichero de traducciones compilado. Si es así, se carga en memoria y se hace que cualquier intento de traducción utilice llamadas a la extensión gettext de PHP. Podéis encontrar el parche adjunto al artículo.

Una vez aplicado el mismo, habrá que compilar un fichero de traducciones. Para ello, primero se necesita un fichero .po con todas las cadenas traducidas de vuestra web. Esto se consigue en admin/build/translate/export. Tras esto, obtendréis un fichero con nombre es.po (suponiendo que hemos exportado el idioma castellano).

La compilación del fichero se hace de la siguiente manera:

msgfmt -o messages.mo es.po

Con lo que obtendréis un fichero messages.mo. Este proceso puede dar algunos errores y es normal que haya que intentarlo más de una vez, sobre todo porque algunas cadenas aparecerán duplicadas en el fichero .po y necesitarás eliminar las duplicidades del fichero manualmente.

Una vez tenemos el fichero compilado, debemos ubicarlo en la ruta /sites/{domain}/locale/es/LC_MESSAGES/messages.mo dentro del directorio raiz de la instalación Drupal. Nótese que la ruta incluye un directorio con el nombre del idioma exportado, en este caso "es".

Con estos pasos, Drupal ya empezará a tomar las traducciones del fichero binario que hemos compilado.

Benchmarks

Hemos realizado algunas pruebas de estrés usando apache benchmark y el módulo devel. Hay que tener en cuenta que las mejoras en cuanto a consultas MySQL y memoria se toman como reducciones respecto al valor normal en Drupal, mientras que las de peticiones por segundo se toman como aumentos respecto al valor normal. Las pruebas han sido realizadas sobre un equipo MacBook Pro Core 2 Duo 2.66 Ghz y 4 GB RAM, en una instalación Drupal 6. Estos son los resultados con una instalación limpia de Drupal:

Clean Drupal 6 Install, Front page, Anonymous, No Cache.

 NormalCon parche gettextMejora
Peticiones / segundo33.436.479.19%
Consultas MySQL312422.58%
Memoria1.030.957.77%

Hemos probado también a desactivar la caché de locales.

 Peticiones / segundo
Sin cache locale29.71
Drupal Normal33.98
Con parche gettext39.63

Y estos son los resultados para una instalación Drupal más compleja, con algunos campos cck creados de varios tipos, incluyendo imágenes y nodereferences. También se crearon (usando devel generate) 50 categorías, 100 usuarios, y 100 nodos.

Drupal, CCK fields, filefield, imagecache, 100 users, 100 nodes, Front page, Anonymous, No cache.

 NormalCon parche gettextMejora
Consultas MySQL14612216.44%
Memoria4.494.265.12%
    
Peticiones / segundo (anónimo)   
Concurrencia: 1 petición5.866.032.90%
Concurrencia: 5 peticiones10.3910.531.35%
Concurrencia: 25 peticiones8.8310.0914.27%
    
Peticiones / segundo (autenticado)   
Concurrencia: 1 petición4.134.314.36%
Concurrencia: 5 peticiones6.287.0512.26%
Concurrencia: 25 peticiones6.777.043.99%
    

También hemos probado a deshabilitar la caché del módulo locale. Esto se puede hacer poniendo el valor de la variable locale_cache_strings a 0. Por supuesto, en este caso, ya que Drupal tiene que obtener todas las traducciones desde la base de datos, la mejora en rendimiento es mucho más grande.

 NormalCon parche gettextMejora
Consultas MySQL37012267.03%
Memoria4.484.264.91%
    
Peticiones / segundo (anónimo)   
Concurrencia: 1 petición2.984.3445.64%
Concurrencia: 5 peticiones4.767.3454.20%
Concurrencia: 25 peticiones4.347.1364.29%
    

Unicef.es Portada

Seguimos con el benchmark, esta vez de una web real, compleja y con gran cantidad de contenido. Para la portada obtenemos los siguientes números:

 Peticiones / segundoMejora
Sin Cache de locale0.690%
Drupal Normal0.758.70%
Con parche gettext0.8218.84%

Unicef.es Sección Actualidad

Para la sección actualidad, los resultados son los siguientes:

 Peticiones / segundoMejora
Sin Cache de locale0.420%
Drupal Normal0.4711.90%
Con parche gettext0.5121.43%

Unicef.es Nodo Noticia

Por último, si visitamos un nodo de tipo noticia, obtenemos la siguiente gráfica:

 Peticiones / segundoMejora
Sin Cache de locale0.540%
Drupal Normal0.6112.96%
Con parche gettext0.6724.07%

Conclusión

Como se puede apreciar en los benchmarks la mejora se presenta en todos los casos y para todos los parámetros medidos. Dependiendo de la instalación los resultados pueden ser más interesantes, pero en todos los casos se produce una mejora de nuestro sistema.

Referencias: