Archivo de la etiqueta: Optimización

Herramientas

Habilitar el opcache que viene con php ( >= 5.5 ) en xampp

Ya en el futuro de va a demostrar si este nuevo opcache es mejor que los ya conocidos, pero de momento es el ÚNICO que funciona razonablemente bien en WINDOWS.

Edita tu “php.ini” y pega esto al final del archivo (si tenes configurado xdebug, al opcache ponelo por encima de este)

[Opcache]
; poné el path real donde esté alojado php_opcache.dll
zend_extension = "C:\xampp\php\ext\php_opcache.dll"
opcache.memory_consumption = 500
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=60
opcache.fast_shutdown=1
opcache.enable_cli=1

Y listo, tenemos un motivo menos de sufrimiento a la hora de programar en este SO.

Chau!

performance

Mejorando el rendimiento en Drupal 7: Memcached y Entity cache

En este post vamos a enfocarnos sobre Memcached tratando de mostrar las ventajas a la hora de utilizarlo en Drupal 7.

Memcached para los que no lo conozcan, es un data cache basado en RAM.

Usar Memcached en Drupal tiene un beneficio altísimo tanto para usuarios logueados como para anónimos. ¿Por que?, fácil, Drupal para cachear utiliza la base de datos como almacén para dicho cache, y esto es costoso. Cada vez que guarda algo en cache o lo pide, estamos haciendo una query a la DB, y aunque toda tu DB este cacheada (mysql tiene su propio cache) Drupal siempre va a tener un importante overhead solo por tener que pedir a la DB este cache.

Técnicamente hablando el tema es así: Estés o no logueado, Drupal usa cache_get() y cache_set(). Luego, estas funciones delegan la tarea de cacheo a la clase que se encargue en ese momento de almacenar y devolver los datos cacheados. Una instalación estándar trae una clase llamada “DrupalDatabaseCache” que usa como backend storage la propia DB de Drupal. El módulo Memcache API simplemente proporciona su propia clase (MemCacheDrupal) que hace lo mismo pero mandando el cache a Memcache.

Memcache se presenta como una muy buena solución a este escollo ya que fue diseñado para ser usado como cache, ofreciendo un overhead mínimo y una velocidad de respuesta muy superior.

Bueno, vamos al lío.

Maquina de pruebas:

Para hacer las pruebas he usado la instalación de Drupal “Un mal día para este Drupal“.
Las pruebas las hice sobre usuarios anónimos, logueados y el propio admin que es el que mas suele sufrir en terminos de performance porque ejecuta código extra por los privilegios que conlleva.

Usuarios anónimos:

Pruebas con el cache de Drupal desactivado:

Sin Memcache

  • Executed 2312 queries in 199.42 ms.
  • Page execution time was 4791.87 ms.
  • PHP peak=59.25 MB.

Con Memcache

  • Executed 1226 queries in 71.77 ms.
  • Page execution time was 3892.39 ms.
  • PHP peak=57 MB.

Con Memcache y entity cache:

  • Executed 398 queries in 39.88 ms.
  • Page execution time was 3450.76 ms.
  • PHP peak=56 MB.
Ahora con el cache de Drupal y bloques activado:

Sin Memcache

  • Executed 2312 queries in 167.15 ms.
  • Page execution time was 4037.62 ms.
  • PHP peak=59.25 MB.

Con Memcache

  • Executed 1186 queries in 66 ms.
  • Page execution time was 3927.52 ms.
  • PHP peak=57.75 MB.

Con Memcache y entity cache:

  • Executed 377 queries in 30.31 ms.
  • Page execution time was 3534.07 ms.
  • PHP peak=55.25 MB.

Usuarios logueados

Pruebas con el cache de Drupal desactivado:

Sin Memcache

  • Executed 2324 queries in 162.27 ms.
  • Page execution time was 4033.2 ms.
  • PHP peak=58.75 MB.

Con Memcache

  • Executed 1237 queries in 73.47 ms.
  • Page execution time was 4028.68 ms.
  • PHP peak=56.25 MB.

Con Memcache y entity cache:

  • Executed 396 queries in 26.19 ms.
  • Page execution time was 3530.29 ms.
  • PHP peak=56 MB.
Ahora con el cache de Drupal y bloques activado:

Sin Memcache

  • Executed 2262 queries in 182.59 ms.
  • Page execution time was 4286.79 ms.
  • PHP peak=58 MB.

Con Memcache

  • Executed 1237 queries in 56.45 ms.
  • Page execution time was 3716.37 ms.
  • PHP peak=56.25 MB.

Con Memcache y entity cache:

  • Executed 379 queries in 27.97 ms.
  • Page execution time was 4072.24 ms.
  • PHP peak=55.25 MB.

Usuarios con rol “administrator”

Pruebas con el cache de Drupal desactivado:

Sin Memcache

  • Executed 3106 queries in 231.33 ms.
  • Page execution time was 5588.66 ms.
  • PHP peak=66.75 MB.

Con Memcache

  • Executed 1812 queries in 89.79 ms.
  • Page execution time was 4701.39 ms.
  • PHP peak=64.5 MB.

Con Memcache y entity cache:

  • Executed 1133 queries in 68.43 ms.
  • Page execution time was 4563.24 ms.
  • PHP peak=64.25 MB.
Ahora con el cache de Drupal y bloques activado:

Sin Memcache

  • Executed 3104 queries in 219.49 ms.
  • Page execution time was 5510.96 ms.
  • PHP peak=67 MB.

Con Memcache

  • Executed 1816 queries in 107.06 ms.
  • Page execution time was 4931.99 ms.
  • PHP peak=64.25 MB.

Con Memcache y entity cache:

  • Executed 1133 queries in 71.71 ms.
  • Page execution time was 4641.69 ms.
  • PHP peak=64.25 MB.

Resumiendo:

Gráfica comparativa de Memcache y Entity cache en Drupal

Como podemos ver, cuando usamos Memcache, las queries a la db bajan un nada despreciable 50%. Estas query que ya no están, son “cache” que pasan a ser gestionadas por Memcache, quien como ya comentamos, es mucho mas eficiente a la hora de servir contenidos cacheados (insisto que está diseñado para ello, ergo es muy difícil que mysql lo haga mejor).

Pero para mas inri, al activar Entity cache, automágicamente las query a la DB bajan un 60% mas sobre lo que ya había conseguido Memcache. Esto es gracias a que este modulo implementa una capa de cache a todas las entidades del core de Drupal mas todas las entidades creadas por terceros que implementen la api en entity cache para dejarse cachear.

Conclusiones:

  • Entre Memcache y entity cache hemos logrado una reducción media del 85% de accesos a la DB (awesomeeeee!).
  • El beneficio mas evidente en el uso de Memcache y entity cache juntos es el de una reducción drástica en las
    consultas que se hacen a la DB, lo que viene especialmente bien ya que cuando una pagina en Drupal comienza a
    recibir muchas visitas, la db es lo primero que sufre.
  • Luego de estas pruebas podemos concluir que si usar Memcache es una buena idea, combinarlo con entity cache es
    una excelente idea.
  • Memcache y entity cache funcionan tanto en usuarios logueados como anónimos.
  • Es evidente que mientras mas cosas cacheemos en Drupal, mejor va a funcionar esta solución. En especial me
    refiero a views, y panels. Usen el cache que estos módulos tienen, para que Memcache pueda gestionarlos. En una
    prueba rapida que hice conseguí rebajar aun mas la cantidad de queries a solo 95 contra las 377 que ya
    lográbamos usando Memcache y entity cache
    .

Happy performance!

Druplicon

Drupal: Porque usar Drupal.behaviors en lugar de $(document).ready();

Durante mucho tiempo estuve usando $(document).ready(); para poner mi js en Drupal, y funcionaba la mar de bien. Esto me permitía ejecutar javascript inmediatamente después que el DOM estuviera cargado evitando así errores de referencias a objetos que todavía no existieran al querer manipularlos.

Ahora bien, hay un problema que vamos a encontrar por medio de un ejemplo simple:

Si tuviéramos un listado de nodos y a ese listado hiciéramos que al pinchar sobre sus enlaces hiciera un alert de su atributo “title” usando jQuery:

jQuery(document).ready(function($) {
    $("#listado_de_nodos a").click(function(e) {
        alert($(this).attr("title"));
    });
});

¿Qué pasa si por medio de AJAX se agregaran nuevos nodos? te lo digo, que no reaccionarían al hacer click sobre ellos, y es por que el método .click() de jQuery se ejecuta una sola vez en busca de elementos que macheen con su criterio y una vez finalizado ya está, no hace mas. Es un comportamiento de lo mas entendible ya que imaginemos que estuviera escaneando constantemente por nuevos elementos ese selector mas los otros 50 que estemos usando para hacer mas cosas…. Google Chrome lo soportaría sin apenas darle carga al procesador y RAM, pero piensen en la basura de IE…..

Perdonen que me vaya por las ramas, como les decía, dado el problema que se planteo para el listado de nodos que di como ejemplo, se implemento una solucion (bueno cubre mas problemas pero este es de los mas comunes) la solución fue usar al objeto Drupal.behaviors a modo de controlador. Drupal.behaviors relanza todas las funciones que almacena por cada vez que se lance una petición AJAX, dándonos la oportunidad de re procesar cosas. Así pues en el ejemplo anterior lo podemos poner dentro de un behavior para poder aplicar nuestra funcionalidad incluso a los nuevos elementos provenientes de la petición:

Drupal.behaviors.alertarEnlaces = function(context) {
    $("#listado_de_nodos a").click(function(e) {
        alert($(this).attr("title"));
    });
}

Como ven lo único que hay que reemplazar en nuestros actuales ficheros de javascript es jQuery(document).ready(function($) {}) por Drupal.behaviors.alertarEnlaces = function(context) {} y no se preocupen por el hecho de que su código este ahora asignado dentro de una función(“Drupal.behaviors.alertarEnlace() “), porque esta se ejecuta solita, y veanlo incluso como una ventaja, pueden invocarla ustedes mismos cuando quieran ademas.